// Prism Translate — central storage + defaults.
// Single source of truth for settings/providers/prompts/glossary/usage.
// Imported by both the service worker and extension pages; both share chrome.storage.local.

import { BUILTIN_PROMPTS } from "./prompts.js";

export const LANGS = [
  { code: "auto", name: "自动检测" },
  { code: "zh-CN", name: "简体中文" },
  { code: "zh-TW", name: "繁體中文" },
  { code: "en", name: "English" },
  { code: "ja", name: "日本語" },
  { code: "ko", name: "한국어" },
  { code: "fr", name: "Français" },
  { code: "de", name: "Deutsch" },
  { code: "es", name: "Español" },
  { code: "ru", name: "Русский" },
  { code: "pt", name: "Português" },
  { code: "it", name: "Italiano" },
  { code: "ar", name: "العربية" },
  { code: "hi", name: "हिन्दी" },
  { code: "th", name: "ไทย" },
  { code: "vi", name: "Tiếng Việt" },
];

export const PROVIDER_TYPES = {
  openai: {
    label: "OpenAI 兼容",
    note: "OpenAI / DeepSeek / Qwen / Moonshot / 本地 Ollama 等任意 OpenAI 兼容端点",
    defaultBase: "https://api.openai.com/v1",
    defaultModel: "gpt-4o-mini",
  },
  claude: {
    label: "Anthropic Claude",
    note: "Claude 系列，浏览器直连需开放 CORS（已自动附加请求头）",
    defaultBase: "https://api.anthropic.com",
    defaultModel: "claude-haiku-4-5-20251001",
  },
  gemini: {
    label: "Google Gemini",
    note: "Gemini 系列（generativelanguage.googleapis.com）",
    defaultBase: "https://generativelanguage.googleapis.com",
    defaultModel: "gemini-2.0-flash",
  },
  deepl: {
    label: "DeepL",
    note: "传统机器翻译，速度快、成本低，不支持自定义提示词",
    defaultBase: "https://api-free.deepl.com",
    defaultModel: "deepl",
  },
};

// Approximate prices in USD per 1M tokens [input, output]. Used for the cost dashboard.
// Unknown models fall back to null (shown as "—").
export const PRICE_TABLE = {
  "gpt-4o": [2.5, 10],
  "gpt-4o-mini": [0.15, 0.6],
  "gpt-4.1": [2, 8],
  "gpt-4.1-mini": [0.4, 1.6],
  "o4-mini": [1.1, 4.4],
  "deepseek-chat": [0.27, 1.1],
  "deepseek-v3": [0.27, 1.1],
  "claude-haiku-4-5-20251001": [1, 5],
  "claude-sonnet-4-6": [3, 15],
  "claude-opus-4-8": [15, 75],
  "gemini-2.0-flash": [0.1, 0.4],
  "gemini-2.5-flash": [0.3, 2.5],
  "gemini-2.5-pro": [1.25, 10],
  "qwen-mt-turbo": [0.17, 0.49],
  "qwen-plus": [0.4, 1.2],
};

// Personal seed: the user's working DashScope/Qwen key, so the extension translates
// the moment it is loaded. This is a local, unpacked, single-user build — if you ever
// share this folder, rotate this key. Edit/remove it on the 服务商 page anytime.
export const SEED_PROVIDER = {
  id: "qwen-seed",
  type: "openai",
  name: "Qwen (DashScope)",
  baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
  apiKey: "",
  model: "qwen-plus",
  temperature: 0.2,
  enabled: true,
};

export const DEFAULT_SETTINGS = {
  targetLang: "zh-CN",
  sourceLang: "auto",
  defaultProvider: "qwen-seed", // provider id; resolved to first enabled if empty
  displayStyle: "underline",  // underline | dashed | highlight | dim | block | replace
  triggerMode: "manual",      // manual | auto
  scenario: "general",        // active AI-expert prompt id
  batchSize: 8,
  concurrency: 4,
  enableCache: true,
  theme: "dark",              // dark | light
  selectionBubble: true,
  videoSubs: true,            // YouTube bilingual subtitles
};

function uid(prefix = "p") {
  // Prefer crypto.randomUUID (available in MV3 service workers and extension pages).
  return prefix + "_" + (crypto?.randomUUID ? crypto.randomUUID().slice(0, 8) : Math.abs(hashStr(prefix + performance.now())).toString(36));
}

export function hashStr(s) {
  let h = 0;
  for (let i = 0; i < s.length; i++) {
    h = (h << 5) - h + s.charCodeAt(i);
    h |= 0;
  }
  return h;
}

export function defaultProviders() {
  return [{ ...SEED_PROVIDER }];
}

export function defaultPrompts() {
  return BUILTIN_PROMPTS.map((p) => ({ ...p, builtin: true }));
}

export async function getState() {
  const raw = await chrome.storage.local.get([
    "settings",
    "providers",
    "prompts",
    "glossary",
    "usage",
  ]);
  const settings = { ...DEFAULT_SETTINGS, ...(raw.settings || {}) };
  let providers = Array.isArray(raw.providers) ? raw.providers : defaultProviders();
  let prompts = Array.isArray(raw.prompts) && raw.prompts.length ? raw.prompts : defaultPrompts();
  // Re-merge builtin prompts so upgrades pick up new presets without clobbering custom ones.
  const customPrompts = prompts.filter((p) => !p.builtin);
  prompts = [...defaultPrompts(), ...customPrompts];
  const glossary = Array.isArray(raw.glossary) ? raw.glossary : [];
  const usage = raw.usage || {};
  return { settings, providers, prompts, glossary, usage };
}

export async function saveSettings(settings) {
  await chrome.storage.local.set({ settings });
}
export async function saveProviders(providers) {
  await chrome.storage.local.set({ providers });
}
export async function savePrompts(prompts) {
  // Persist only custom prompts; builtins are re-merged on read.
  await chrome.storage.local.set({ prompts: prompts.filter((p) => !p.builtin) });
}
export async function saveGlossary(glossary) {
  await chrome.storage.local.set({ glossary });
}

export function newProvider(type = "openai") {
  const t = PROVIDER_TYPES[type];
  return {
    id: uid(type),
    type,
    name: t.label,
    baseURL: t.defaultBase,
    apiKey: "",
    model: t.defaultModel,
    temperature: 0.2,
    enabled: true,
  };
}

export function newPrompt() {
  return {
    id: uid("expert"),
    name: "自定义专家",
    system:
      "你是专业翻译。把内容翻译为{{target}}，只输出译文，不要解释。保持术语与格式一致。",
    builtin: false,
  };
}

// Usage accounting. Serialized through a promise chain to avoid read-modify-write races.
let usageLock = Promise.resolve();
export function addUsage(providerId, { model, inputTokens = 0, outputTokens = 0, chars = 0, requests = 1 }) {
  usageLock = usageLock.then(async () => {
    const { usage } = await chrome.storage.local.get("usage");
    const u = usage || {};
    const cur = u[providerId] || {
      requests: 0,
      inputTokens: 0,
      outputTokens: 0,
      chars: 0,
      cost: 0,
      model: model || "",
    };
    cur.requests += requests;
    cur.inputTokens += inputTokens;
    cur.outputTokens += outputTokens;
    cur.chars += chars;
    cur.model = model || cur.model;
    const price = PRICE_TABLE[model];
    if (price) {
      cur.cost += (inputTokens / 1e6) * price[0] + (outputTokens / 1e6) * price[1];
    }
    u[providerId] = cur;
    await chrome.storage.local.set({ usage: u });
  });
  return usageLock;
}

export async function resetUsage() {
  await chrome.storage.local.set({ usage: {} });
}

export function langName(code) {
  return LANGS.find((l) => l.code === code)?.name || code;
}
