const STORAGE_KEY = "blackeagleConfigs";
const STATUS_DURATION = 4000;
const TASK_STORAGE_KEY = "blackeagleTasks";
const MORE_STORAGE_KEY = "blackeagleMoreConfig";

const storage = (() => {
  const chromeStorage = typeof chrome !== "undefined" && chrome?.storage?.local;
  if (chromeStorage) {
    return {
      async get() {
        return new Promise((resolve, reject) => {
          chrome.storage.local.get([STORAGE_KEY], (result) => {
            if (chrome.runtime?.lastError) {
              reject(chrome.runtime.lastError);
              return;
            }
            resolve(result[STORAGE_KEY] ?? []);
          });
        });
      },
      async set(configs) {
        return new Promise((resolve, reject) => {
          chrome.storage.local.set({ [STORAGE_KEY]: configs }, () => {
            if (chrome.runtime?.lastError) {
              reject(chrome.runtime.lastError);
              return;
            }
            resolve();
          });
        });
      },
    };
  }

  // Fallback to localStorage when the extension APIs are unavailable (e.g. local dev preview).
  return {
    async get() {
      try {
        const raw = localStorage.getItem(STORAGE_KEY);
        return raw ? JSON.parse(raw) : [];
      } catch (error) {
        console.error("Unable to read configs from localStorage", error);
        return [];
      }
    },
    async set(configs) {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(configs));
    },
  };
})();

// Additional config storage (e.g., Notion token)
const moreStorage = (() => {
  const chromeStorage = typeof chrome !== "undefined" && chrome?.storage?.local;
  if (chromeStorage) {
    return {
      async get() {
        return new Promise((resolve, reject) => {
          chrome.storage.local.get([MORE_STORAGE_KEY], (result) => {
            if (chrome.runtime?.lastError) {
              reject(chrome.runtime.lastError);
              return;
            }
            resolve(result[MORE_STORAGE_KEY] ?? {});
          });
        });
      },
      async set(config) {
        return new Promise((resolve, reject) => {
          chrome.storage.local.set({ [MORE_STORAGE_KEY]: config }, () => {
            if (chrome.runtime?.lastError) {
              reject(chrome.runtime.lastError);
              return;
            }
            resolve();
          });
        });
      },
    };
  }

  return {
    async get() {
      try {
        const raw = localStorage.getItem(MORE_STORAGE_KEY);
        return raw ? JSON.parse(raw) : {};
      } catch (error) {
        console.error("Unable to read more config from localStorage", error);
        return {};
      }
    },
    async set(config) {
      localStorage.setItem(MORE_STORAGE_KEY, JSON.stringify(config || {}));
    },
  };
})();

// Task storage goes through background to ensure alarms are rescheduled.
const taskApi = {
  async list() {
    if (chrome?.runtime?.id) {
      return new Promise((resolve) => {
        chrome.runtime.sendMessage({ type: "TASK_LIST" }, (res) => {
          const err = chrome.runtime.lastError;
          if (err || !res?.success) {
            console.warn("TASK_LIST failed", err || res?.error);
            resolve([]);
            return;
          }
          resolve(res.tasks || []);
        });
      });
    }
    // fallback (preview without extension runtime)
    try {
      const raw = localStorage.getItem(TASK_STORAGE_KEY);
      return raw ? JSON.parse(raw) : [];
    } catch (e) {
      return [];
    }
  },
  async upsert(task) {
    if (chrome?.runtime?.id) {
      return new Promise((resolve, reject) => {
        chrome.runtime.sendMessage({ type: "TASK_UPSERT", payload: task }, (res) => {
          const err = chrome.runtime.lastError;
          if (err || !res?.success) {
            reject(err || res?.error || "TASK_UPSERT failed");
            return;
          }
          resolve(res.task);
        });
      });
    }
    // fallback
    const list = await taskApi.list();
    const id = task.id || `task_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;
    const now = new Date().toISOString();
    const existing = list.find((t) => t.id === id);
    const nextTask = existing ? { ...existing, ...task, id, updatedAt: now, createdAt: existing.createdAt || now } : { ...task, id, createdAt: task.createdAt || now, updatedAt: now };
    const next = existing ? list.map((t) => (t.id === id ? nextTask : t)) : [...list, nextTask];
    localStorage.setItem(TASK_STORAGE_KEY, JSON.stringify(next));
    return next.find((t) => t.id === id);
  },
  async remove(id) {
    if (chrome?.runtime?.id) {
      return new Promise((resolve, reject) => {
        chrome.runtime.sendMessage({ type: "TASK_DELETE", payload: { id } }, (res) => {
          const err = chrome.runtime.lastError;
          if (err || !res?.success) {
            reject(err || res?.error || "TASK_DELETE failed");
            return;
          }
          resolve();
        });
      });
    }
    const list = await taskApi.list();
    const next = list.filter((t) => t.id !== id);
    localStorage.setItem(TASK_STORAGE_KEY, JSON.stringify(next));
  },
  async runNow(id) {
    if (chrome?.runtime?.id) {
      return new Promise((resolve, reject) => {
        chrome.runtime.sendMessage({ type: "TASK_RUN_NOW", payload: { id } }, (res) => {
          const err = chrome.runtime.lastError;
          if (err || !res?.success) {
            reject(err || res?.error || "TASK_RUN_NOW failed");
            return;
          }
          resolve();
        });
      });
    }
    // fallback (preview): mark lastRunAt locally
    const list = await taskApi.list();
    const now = new Date().toISOString();
    const next = list.map((t) => (t.id === id ? { ...t, lastRunAt: now, updatedAt: now } : t));
    localStorage.setItem(TASK_STORAGE_KEY, JSON.stringify(next));
  },
};

const state = {
  configs: [],
  editingId: null,
  statusTimer: null,
  section: "llm",
  tasks: [],
  editingTaskId: null,
  taskStatusTimer: null,
  moreConfig: { notionToken: "" },
  moreStatusTimer: null,
};

const notifyRefresh = () => {
  const payload = { type: "REFRESH" };
  if (typeof chrome !== "undefined" && chrome?.runtime?.id) {
    try {
      chrome.runtime.sendMessage(payload, () => {
        const err = chrome.runtime?.lastError;
        if (err) {
          console.debug("REFRESH message warning", err);
        }
      });
      return;
    } catch (error) {
      console.debug("REFRESH message failed", error);
    }
  }

  if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
    window.dispatchEvent(new CustomEvent("REFRESH", { detail: payload }));
  }
};

const elements = {
  form: document.getElementById("configForm"),
  formTitle: document.getElementById("formTitle"),
  submitBtn: document.getElementById("submitBtn"),
  resetBtn: document.getElementById("resetBtn"),
  status: document.getElementById("status"),
  configId: document.getElementById("configId"),
  name: document.getElementById("name"),
  apiKey: document.getElementById("apiKey"),
  baseURL: document.getElementById("baseURL"),
  apiVersion: document.getElementById("apiVersion"),
  model: document.getElementById("model"),
  llmType: document.getElementById("llmType"),
  configList: document.getElementById("configList"),
  configCounter: document.getElementById("configCounter"),
  emptyState: document.getElementById("emptyState"),
  tabs: Array.from(document.querySelectorAll(".tab-btn")),
  sections: Array.from(document.querySelectorAll("main.grid")),
  taskForm: document.getElementById("taskForm"),
  taskFormTitle: document.getElementById("taskFormTitle"),
  taskSubmitBtn: document.getElementById("taskSubmitBtn"),
  taskResetBtn: document.getElementById("taskResetBtn"),
  taskStatus: document.getElementById("taskStatus"),
  taskId: document.getElementById("taskId"),
  taskName: document.getElementById("taskName"),
  taskInstruction: document.getElementById("taskInstruction"),
  intervalMinutes: document.getElementById("intervalMinutes"),
  onceAt: document.getElementById("onceAt"),
  taskEnabled: document.getElementById("taskEnabled"),
  taskList: document.getElementById("taskList"),
  taskCounter: document.getElementById("taskCounter"),
  taskEmpty: document.getElementById("taskEmpty"),
  configExportBtn: document.getElementById("configExportBtn"),
  configImportBtn: document.getElementById("configImportBtn"),
  configImportInput: document.getElementById("configImportInput"),
  taskExportBtn: document.getElementById("taskExportBtn"),
  taskImportBtn: document.getElementById("taskImportBtn"),
  taskImportInput: document.getElementById("taskImportInput"),
  moreForm: document.getElementById("moreForm"),
  moreStatus: document.getElementById("moreStatus"),
  notionToken: document.getElementById("notionToken"),
  moreSubmitBtn: document.getElementById("moreSubmitBtn"),
  moreResetBtn: document.getElementById("moreResetBtn"),
};

const createId = () => crypto?.randomUUID?.() ?? `cfg_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;
const createTaskId = () => `task_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;

const maskApiKey = (value) => {
  if (!value) return "—";
  return value.length <= 8 ? `${value.slice(0, 2)}••••` : `${value.slice(0, 4)}••••${value.slice(-2)}`;
};

const formatHost = (url) => {
  try {
    return new URL(url).host;
  } catch (_) {
    return url;
  }
};

const setStatus = (messageOrKey, variant = "info", vars) => {
  if (!elements.status) return;
  let text = "";
  if (typeof i18n !== "undefined" && i18n.t) {
    if (typeof messageOrKey === "string") {
      text = i18n.t(messageOrKey, vars) || messageOrKey;
    } else if (messageOrKey && messageOrKey.key) {
      text = i18n.t(messageOrKey.key, messageOrKey.vars) || "";
    } else {
      text = String(messageOrKey);
    }
  } else {
    text = typeof messageOrKey === "string" ? messageOrKey : messageOrKey && messageOrKey.key ? messageOrKey.key : String(messageOrKey);
  }

  elements.status.textContent = text;
  elements.status.style.color = variant === "error" ? "var(--danger)" : "var(--muted)";

  if (state.statusTimer) {
    clearTimeout(state.statusTimer);
  }

  state.statusTimer = setTimeout(() => {
    elements.status.textContent = "";
  }, STATUS_DURATION);
};

const setTaskStatus = (messageOrKey, variant = "info", vars) => {
  if (!elements.taskStatus) return;
  let text = "";
  if (typeof i18n !== "undefined" && i18n.t) {
    if (typeof messageOrKey === "string") {
      text = i18n.t(messageOrKey, vars) || messageOrKey;
    } else if (messageOrKey && messageOrKey.key) {
      text = i18n.t(messageOrKey.key, messageOrKey.vars) || "";
    } else {
      text = String(messageOrKey);
    }
  } else {
    text = typeof messageOrKey === "string" ? messageOrKey : messageOrKey && messageOrKey.key ? messageOrKey.key : String(messageOrKey);
  }

  elements.taskStatus.textContent = text;
  elements.taskStatus.style.color = variant === "error" ? "var(--danger)" : "var(--muted)";

  if (state.taskStatusTimer) {
    clearTimeout(state.taskStatusTimer);
  }

  state.taskStatusTimer = setTimeout(() => {
    elements.taskStatus.textContent = "";
  }, STATUS_DURATION);
};

const setMoreStatus = (messageOrKey, variant = "info", vars) => {
  if (!elements.moreStatus) return;
  let text = "";
  if (typeof i18n !== "undefined" && i18n.t) {
    if (typeof messageOrKey === "string") {
      text = i18n.t(messageOrKey, vars) || messageOrKey;
    } else if (messageOrKey && messageOrKey.key) {
      text = i18n.t(messageOrKey.key, messageOrKey.vars) || "";
    } else {
      text = String(messageOrKey);
    }
  } else {
    text = typeof messageOrKey === "string" ? messageOrKey : messageOrKey && messageOrKey.key ? messageOrKey.key : String(messageOrKey);
  }

  elements.moreStatus.textContent = text;
  elements.moreStatus.style.color = variant === "error" ? "var(--danger)" : "var(--muted)";

  if (state.moreStatusTimer) {
    clearTimeout(state.moreStatusTimer);
  }

  state.moreStatusTimer = setTimeout(() => {
    elements.moreStatus.textContent = "";
  }, STATUS_DURATION);
};

const downloadJson = (filename, payload) => {
  try {
    const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = filename;
    link.click();
    URL.revokeObjectURL(url);
  } catch (error) {
    console.error("Download JSON failed", error);
  }
};

const normalizeConfigImport = (data) => {
  if (Array.isArray(data)) return data;
  if (Array.isArray(data?.configs)) return data.configs;
  return [];
};

const normalizeTaskImport = (data) => {
  if (Array.isArray(data)) return data;
  if (Array.isArray(data?.tasks)) return data.tasks;
  return [];
};

const toIsoStringSafe = (value) => {
  if (!value) return undefined;
  const d = new Date(value);
  return Number.isNaN(d.getTime()) ? undefined : d.toISOString();
};

const updateCounter = () => {
  const count = state.configs.length;
  if (typeof i18n !== "undefined" && i18n.t) {
    elements.configCounter.textContent = i18n.t("configCounter", { count });
  } else {
    elements.configCounter.textContent = `${count} ${count === 1 ? "config" : "configs"}`;
  }
};

const renderConfigs = () => {
  elements.configList.innerHTML = "";

  if (!state.configs.length) {
    elements.emptyState.style.display = "block";
    updateCounter();
    return;
  }

  elements.emptyState.style.display = "none";

  state.configs
    .sort((a, b) => new Date(b.updatedAt ?? b.createdAt) - new Date(a.updatedAt ?? a.createdAt))
    .forEach((cfg) => {
      const card = document.createElement("article");
      card.className = "config-card";
      card.dataset.id = cfg.id;

      const displayName = cfg.name?.trim() || formatHost(cfg.baseURL);

      card.innerHTML = `
        <h3>${displayName}</h3>
        <dl>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtModelName") : "Model Name"}</dt>
            <dd>${cfg.name || "—"}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtApiKey") : "API Key"}</dt>
            <dd>${maskApiKey(cfg.apiKey)}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtBaseUrl") : "Base URL"}</dt>
            <dd>${cfg.baseURL}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtApiVersion") : "API Version"}</dt>
            <dd>${cfg.apiVersion || "—"}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtModel") : "Model"}</dt>
            <dd>${cfg.model}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtLlmType") : "LLM Type"}</dt>
            <dd>${cfg.llmType ?? "talk"}</dd>
          </div>
        </dl>
        <div class="card-actions">
          <button type="button" data-action="edit" data-id="${cfg.id}" class="secondary">${typeof i18n !== "undefined" && i18n.t ? i18n.t("btnEdit") : "Edit"}</button>
          <button type="button" data-action="delete" data-id="${cfg.id}" class="danger">${typeof i18n !== "undefined" && i18n.t ? i18n.t("btnDelete") : "Delete"}</button>
        </div>
      `;

      elements.configList.appendChild(card);
    });

  updateCounter();
};

const updateTaskCounter = () => {
  const count = state.tasks.length;
  if (typeof i18n !== "undefined" && i18n.t) {
    elements.taskCounter.textContent = i18n.t("taskCounter", { count });
  } else {
    elements.taskCounter.textContent = `${count} ${count === 1 ? "task" : "tasks"}`;
  }
};

const formatDateTimeLocal = (iso) => {
  if (!iso) return "—";
  try {
    const d = new Date(iso);
    const yyyy = d.getFullYear();
    const mm = String(d.getMonth() + 1).padStart(2, "0");
    const dd = String(d.getDate()).padStart(2, "0");
    const hh = String(d.getHours()).padStart(2, "0");
    const mi = String(d.getMinutes()).padStart(2, "0");
    return `${yyyy}-${mm}-${dd} ${hh}:${mi}`;
  } catch (_) {
    return iso;
  }
};

const renderTasks = () => {
  elements.taskList.innerHTML = "";

  if (!state.tasks.length) {
    elements.taskEmpty.style.display = "block";
    updateTaskCounter();
    return;
  }

  elements.taskEmpty.style.display = "none";

  state.tasks
    .sort((a, b) => new Date(b.updatedAt ?? b.createdAt ?? 0) - new Date(a.updatedAt ?? a.createdAt ?? 0))
    .forEach((task) => {
      const card = document.createElement("article");
      card.className = "config-card";
      card.dataset.id = task.id;

      const interval = task.intervalMinutes ? (typeof i18n !== "undefined" && i18n.t ? i18n.t("minutesShort", { n: task.intervalMinutes }) : `${task.intervalMinutes} min`) : "—";
      const onceAt = task.onceAt ? formatDateTimeLocal(task.onceAt) : "—";
      const enabled = task.enabled !== false;
      const createdAt = task.createdAt ? formatDateTimeLocal(task.createdAt) : "—";
      const lastRunAt = task.lastRunAt ? formatDateTimeLocal(task.lastRunAt) : "—";

      card.innerHTML = `
        <h3>${task.name || (typeof i18n !== "undefined" && i18n.t ? i18n.t("untitledTask") : "Untitled task")}</h3>
        <dl>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtInstruction") : "Instruction"}</dt>
            <dd>${task.instruction || "—"}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtInterval") : "Interval"}</dt>
            <dd>${interval}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtSchedule") : "Schedule"}</dt>
            <dd>${onceAt}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtStatus") : "Status"}</dt>
            <dd>${enabled ? (typeof i18n !== "undefined" && i18n.t ? i18n.t("enabled") : "Enabled") : typeof i18n !== "undefined" && i18n.t ? i18n.t("disabled") : "Disabled"}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtCreated") : "Created"}</dt>
            <dd>${createdAt}</dd>
          </div>
          <div>
            <dt>${typeof i18n !== "undefined" && i18n.t ? i18n.t("dtLastRun") : "Last run"}</dt>
            <dd>${lastRunAt}</dd>
          </div>
        </dl>
        <div class="card-actions">
          <button type="button" data-action="task-run" data-id="${task.id}" class="secondary">${typeof i18n !== "undefined" && i18n.t ? i18n.t("btnRunNow") : "Run now"}</button>
          <button type="button" data-action="task-edit" data-id="${task.id}" class="secondary">${typeof i18n !== "undefined" && i18n.t ? i18n.t("btnEdit") : "Edit"}</button>
          <button type="button" data-action="task-toggle" data-id="${task.id}" class="secondary">${
            enabled ? (typeof i18n !== "undefined" && i18n.t ? i18n.t("btnPause") : "Pause") : typeof i18n !== "undefined" && i18n.t ? i18n.t("btnResume") : "Resume"
          }</button>
          <button type="button" data-action="task-delete" data-id="${task.id}" class="danger">${typeof i18n !== "undefined" && i18n.t ? i18n.t("btnDelete") : "Delete"}</button>
        </div>
      `;

      elements.taskList.appendChild(card);
    });

  updateTaskCounter();
};

const loadConfigs = async () => {
  try {
    state.configs = await storage.get();
    renderConfigs();
  } catch (error) {
    console.error("Failed to load configs", error);
    setStatus("unableToLoadConfigs", "error");
  }
};

const loadTasks = async () => {
  try {
    state.tasks = await taskApi.list();
    renderTasks();
  } catch (error) {
    console.error("Failed to load tasks", error);
    setTaskStatus("Unable to load tasks", "error");
  }
};

const loadMoreConfig = async () => {
  try {
    const cfg = (await moreStorage.get()) || {};
    state.moreConfig = { notionToken: cfg.notionToken || "" };
    if (elements.notionToken) {
      elements.notionToken.value = state.moreConfig.notionToken || "";
    }
  } catch (error) {
    console.error("Failed to load more config", error);
    setMoreStatus("unableToLoadMore", "error");
  }
};

const persistConfigs = async () => {
  try {
    await storage.set(state.configs);
    renderConfigs();
  } catch (error) {
    console.error("Failed to save configs", error);
    setStatus("savingFailed", "error");
    throw error;
  }
};

const resetForm = () => {
  state.editingId = null;
  elements.form.reset();
  elements.llmType.value = "talk";
  elements.apiVersion.value = "";
  elements.configId.value = "";
  elements.formTitle.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("formTitle") : "Create configuration";
  elements.submitBtn.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("submitSave") : "Save configuration";
};

const resetMoreForm = async () => {
  if (elements.moreForm) elements.moreForm.reset();
  state.moreConfig = { notionToken: "" };
  if (elements.notionToken) elements.notionToken.value = "";
  try {
    await moreStorage.set(state.moreConfig);
  } catch (error) {
    console.error("Reset more config failed", error);
  }
  setMoreStatus("moreCleared");
};

const handleConfigExport = () => {
  if (!state.configs.length) {
    setStatus("noConfigsExport", "error");
    return;
  }
  downloadJson("blackeagle-llm-configs.json", { version: 1, exportedAt: new Date().toISOString(), configs: state.configs });
  setStatus("configsExported");
};

const handleConfigImport = async (file) => {
  if (!file) return;
  try {
    const rawText = await file.text();
    const json = JSON.parse(rawText);
    const incoming = normalizeConfigImport(json);
    if (!incoming.length) {
      setStatus("importNoConfigs", "error");
      return;
    }

    const now = new Date().toISOString();
    const sanitized = incoming
      .map((cfg) => {
        const apiKey = (cfg.apiKey || "").trim();
        const baseURL = (cfg.baseURL || "").trim();
        const model = (cfg.model || "").trim();
        const llmType = (cfg.llmType || "talk").trim();
        if (!apiKey || !baseURL || !model || !llmType) return null;
        return {
          ...cfg,
          id: cfg.id || createId(),
          name: (cfg.name || "").trim() || formatHost(baseURL),
          apiKey,
          baseURL,
          model,
          llmType,
          createdAt: cfg.createdAt || now,
          updatedAt: now,
        };
      })
      .filter(Boolean);

    if (!sanitized.length) {
      setStatus("noValidConfigsImport", "error");
      return;
    }

    const merged = new Map(state.configs.map((cfg) => [cfg.id, cfg]));
    sanitized.forEach((cfg) => {
      const existing = merged.get(cfg.id);
      merged.set(cfg.id, { ...existing, ...cfg, createdAt: existing?.createdAt || cfg.createdAt });
    });
    state.configs = Array.from(merged.values());
    await persistConfigs();
    notifyRefresh();
    setStatus({ key: "importedConfigs", vars: { n: sanitized.length } });
  } catch (error) {
    console.error("Import configs failed", error);
    setStatus("importFailedInvalidJson", "error");
  }
};

const resetTaskForm = () => {
  state.editingTaskId = null;
  elements.taskForm.reset();
  elements.taskEnabled.checked = true;
  elements.taskId.value = "";
  elements.onceAt.value = "";
  elements.taskFormTitle.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("taskFormTitle") : "Create Task";
  elements.taskSubmitBtn.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("submitSave") : "Save Task";
};

const populateForm = (config) => {
  elements.configId.value = config.id;
  elements.name.value = config.name ?? formatHost(config.baseURL);
  elements.apiKey.value = config.apiKey;
  elements.baseURL.value = config.baseURL;
  elements.apiVersion.value = config.apiVersion ?? "";
  elements.model.value = config.model;
  elements.llmType.value = config.llmType ?? "talk";
  state.editingId = config.id;
  elements.formTitle.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("submitUpdate") : "Update configuration";
  elements.submitBtn.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("submitUpdate") : "Update configuration";
};

const populateTaskForm = (task) => {
  state.editingTaskId = task.id;
  elements.taskId.value = task.id;
  elements.taskName.value = task.name || "";
  elements.taskInstruction.value = task.instruction || "";
  elements.intervalMinutes.value = task.intervalMinutes ?? "";
  elements.onceAt.value = task.onceAt ? task.onceAt.slice(0, 16) : ""; // ISO to datetime-local
  elements.taskEnabled.checked = task.enabled !== false;
  elements.taskFormTitle.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("taskFormTitle") : "Update Task";
  elements.taskSubmitBtn.textContent = typeof i18n !== "undefined" && i18n.t ? i18n.t("submitUpdate") : "Update Task";
};

const handleTaskExport = () => {
  if (!state.tasks.length) {
    setTaskStatus("noTasksExport", "error");
    return;
  }
  downloadJson("blackeagle-tasks.json", { version: 1, exportedAt: new Date().toISOString(), tasks: state.tasks });
  setTaskStatus("tasksExported");
};

const handleTaskImport = async (file) => {
  if (!file) return;
  try {
    const rawText = await file.text();
    const json = JSON.parse(rawText);
    const incoming = normalizeTaskImport(json);
    if (!incoming.length) {
      setTaskStatus("importNoTasks", "error");
      return;
    }

    const now = new Date().toISOString();
    const sanitized = incoming
      .map((task) => {
        const instruction = (task.instruction || "").trim();
        if (!instruction) return null;
        const interval = task.intervalMinutes !== undefined ? Number(task.intervalMinutes) : undefined;
        const intervalMinutes = Number.isFinite(interval) ? Math.max(5, interval) : undefined;
        const onceAt = toIsoStringSafe(task.onceAt);

        return {
          ...task,
          id: task.id || createTaskId(),
          name: (task.name || "").trim() || "Untitled Task",
          instruction,
          intervalMinutes,
          onceAt,
          enabled: task.enabled !== false,
          createdAt: task.createdAt || now,
          updatedAt: now,
        };
      })
      .filter(Boolean);

    if (!sanitized.length) {
      setTaskStatus("noValidTasksImport", "error");
      return;
    }

    for (const task of sanitized) {
      await taskApi.upsert(task);
    }

    state.tasks = await taskApi.list();
    renderTasks();
    setTaskStatus({ key: "importedTasks", vars: { n: sanitized.length } });
  } catch (error) {
    console.error("Import tasks failed", error);
    setTaskStatus("importFailedInvalidJson", "error");
  }
};

const handleMoreSubmit = async (event) => {
  event.preventDefault();
  const notionToken = elements.notionToken?.value.trim();

  if (!notionToken) {
    setMoreStatus("notionTokenRequired", "error");
    return;
  }

  const payload = { notionToken };
  try {
    await moreStorage.set(payload);
    state.moreConfig = payload;
    setMoreStatus("notionSaved");
    notifyRefresh();
  } catch (error) {
    console.error("Save Notion token failed", error);
    setMoreStatus("saveFailed", "error");
  }
};

const handleSubmit = async (event) => {
  event.preventDefault();
  const name = elements.name.value.trim();
  const apiKey = elements.apiKey.value.trim();
  const baseURL = elements.baseURL.value.trim();
  const apiVersion = elements.apiVersion.value.trim();
  const model = elements.model.value.trim();
  const llmType = (elements.llmType.value || "talk").trim();

  if (!name || !apiKey || !baseURL || !model || !llmType) {
    setStatus("pleaseFillRequired", "error");
    return;
  }

  const timestamp = new Date().toISOString();

  if (state.editingId) {
    state.configs = state.configs.map((cfg) => (cfg.id === state.editingId ? { ...cfg, name, apiKey, baseURL, apiVersion: apiVersion || undefined, model, llmType, updatedAt: timestamp } : cfg));
    await persistConfigs();
    notifyRefresh();
    setStatus("configUpdated");
  } else {
    const newConfig = {
      id: createId(),
      name,
      apiKey,
      baseURL,
      apiVersion: apiVersion || undefined,
      model,
      llmType,
      createdAt: timestamp,
      updatedAt: timestamp,
    };
    state.configs = [...state.configs, newConfig];
    await persistConfigs();
    notifyRefresh();
    setStatus("configSaved");
  }

  resetForm();
};

const handleTaskSubmit = async (event) => {
  event.preventDefault();
  const name = elements.taskName.value.trim();
  const instruction = elements.taskInstruction.value.trim();
  const intervalMinutesRaw = elements.intervalMinutes.value;
  const onceAtRaw = elements.onceAt.value;
  const enabled = elements.taskEnabled.checked;

  if (!instruction) {
    setTaskStatus("Please provide a task instruction", "error");
    return;
  }

  // Enforce minimum 5-minute interval when provided
  if (intervalMinutesRaw) {
    const n = Number(intervalMinutesRaw);
    if (!Number.isFinite(n) || n < 5) {
      setTaskStatus("Interval cannot be less than 5 minutes", "error");
      return;
    }
  }

  const task = {
    id: state.editingTaskId || undefined,
    name: name || "Untitled Task",
    instruction,
    intervalMinutes: intervalMinutesRaw ? Number(intervalMinutesRaw) : undefined,
    onceAt: onceAtRaw ? new Date(onceAtRaw).toISOString() : undefined,
    enabled,
    // timestamps provided for fallback/local preview; background may override
    updatedAt: new Date().toISOString(),
    createdAt: state.editingTaskId ? undefined : new Date().toISOString(),
  };

  try {
    await taskApi.upsert(task);
    setTaskStatus("Task saved");
    state.tasks = await taskApi.list();
    renderTasks();
    resetTaskForm();
  } catch (error) {
    console.error("Save task failed", error);
    setTaskStatus("Save failed", "error");
  }
};

const handleListClick = async (event) => {
  const button = event.target.closest("button[data-action]");
  if (!button) return;

  const { action, id } = button.dataset;
  const config = state.configs.find((cfg) => cfg.id === id);
  if (!config) return;

  if (action === "edit") {
    populateForm(config);
    elements.apiKey.focus();
    return;
  }

  if (action === "delete") {
    const confirmed = confirm(typeof i18n !== "undefined" && i18n.t ? i18n.t("confirmDeleteConfig") : "Delete this configuration? This cannot be undone.");
    if (!confirmed) return;
    state.configs = state.configs.filter((cfg) => cfg.id !== id);
    await persistConfigs();
    notifyRefresh();
    setStatus("configRemoved");
    if (state.editingId === id) {
      resetForm();
    }
  }
};

const handleTaskListClick = async (event) => {
  const button = event.target.closest("button[data-action]");
  if (!button) return;

  const { action, id } = button.dataset;
  const task = state.tasks.find((t) => t.id === id);
  if (!task) return;

  if (action === "task-edit") {
    populateTaskForm(task);
    elements.taskInstruction.focus();
    return;
  }

  if (action === "task-delete") {
    const confirmed = confirm(typeof i18n !== "undefined" && i18n.t ? i18n.t("confirmDeleteTask") : "Delete this task?");
    if (!confirmed) return;
    try {
      await taskApi.remove(id);
      state.tasks = await taskApi.list();
      renderTasks();
      if (state.editingTaskId === id) resetTaskForm();
      setTaskStatus("taskDeleted");
    } catch (error) {
      console.error("Delete task failed", error);
      setTaskStatus("saveFailed", "error");
    }
    return;
  }

  if (action === "task-toggle") {
    try {
      const nextEnabled = task.enabled === false ? true : false;
      await taskApi.upsert({ ...task, enabled: nextEnabled });
      state.tasks = await taskApi.list();
      renderTasks();
      setTaskStatus(nextEnabled ? "taskResumed" : "taskPaused");
    } catch (error) {
      console.error("Toggle task failed", error);
      setTaskStatus("saveFailed", "error");
    }
    return;
  }

  if (action === "task-run") {
    try {
      await taskApi.runNow(id);
      setTaskStatus("taskSaved");
      // Refresh tasks to reflect latest execution time
      state.tasks = await taskApi.list();
      renderTasks();
    } catch (error) {
      console.error("Run task failed", error);
      setTaskStatus("saveFailed", "error");
    }
    return;
  }
};

const init = () => {
  elements.form.addEventListener("submit", handleSubmit);
  elements.resetBtn.addEventListener("click", () => {
    resetForm();
    setStatus("formCleared");
  });
  elements.configList.addEventListener("click", handleListClick);
  elements.taskForm.addEventListener("submit", handleTaskSubmit);
  elements.taskResetBtn.addEventListener("click", () => {
    resetTaskForm();
    setTaskStatus("formReset");
  });
  elements.taskList.addEventListener("click", handleTaskListClick);

  elements.configExportBtn?.addEventListener("click", handleConfigExport);
  elements.configImportBtn?.addEventListener("click", () => elements.configImportInput?.click());
  elements.configImportInput?.addEventListener("change", async (event) => {
    const file = event.target.files?.[0];
    await handleConfigImport(file);
    event.target.value = "";
  });

  elements.taskExportBtn?.addEventListener("click", handleTaskExport);
  elements.taskImportBtn?.addEventListener("click", () => elements.taskImportInput?.click());
  elements.taskImportInput?.addEventListener("change", async (event) => {
    const file = event.target.files?.[0];
    await handleTaskImport(file);
    event.target.value = "";
  });

  elements.moreForm?.addEventListener("submit", handleMoreSubmit);
  elements.moreResetBtn?.addEventListener("click", () => {
    resetMoreForm();
  });

  elements.tabs.forEach((btn) => {
    btn.addEventListener("click", () => {
      const target = btn.dataset.section;
      state.section = target;
      elements.tabs.forEach((b) => b.classList.toggle("active", b.dataset.section === target));
      elements.sections.forEach((sec) => {
        sec.style.display = sec.dataset.section === target ? "grid" : "none";
      });
    });
  });

  // re-apply translations and re-render dynamic content when language changes
  if (typeof window !== "undefined") {
    window.addEventListener("i18n:change", function () {
      if (typeof i18n !== "undefined" && i18n.apply) i18n.apply();
      renderConfigs();
      renderTasks();
      updateCounter();
      updateTaskCounter();
    });
  }

  loadConfigs();
  loadTasks();
  loadMoreConfig();
};

document.addEventListener("DOMContentLoaded", init);
