import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import { readSavedTheme, resolveTheme, writeSavedTheme } from "./theme.js";
import { translate } from "./i18n.js";

test("resolves explicit and system theme choices", () => {
  assert.equal(resolveTheme("dark", { matches: false }), "dark");
  assert.equal(resolveTheme("light", { matches: true }), "light");
  assert.equal(resolveTheme("system", { matches: true }), "dark");
  assert.equal(resolveTheme("system", { matches: false }), "light");
  assert.equal(resolveTheme("unknown", { matches: true }), "dark");
});

test("persists only supported theme choices", () => {
  const values = new Map();
  const storage = { getItem: (key) => values.get(key) ?? null, setItem: (key, value) => values.set(key, value) };
  assert.equal(readSavedTheme(storage), null);
  writeSavedTheme(storage, "light");
  assert.equal(readSavedTheme(storage), "light");
  writeSavedTheme(storage, "blue");
  assert.equal(readSavedTheme(storage), "light");
});

test("applies the saved theme before the application first renders", async () => {
  const html = await readFile(new URL("../../index.html", import.meta.url), "utf8");
  assert.match(html, /<script>\(\(\) => \{[\s\S]*?localStorage\.getItem\("codexRemote\.theme"\)[\s\S]*?document\.documentElement\.dataset\.theme = resolvedTheme[\s\S]*?<\/script>[\s\S]*?<div id="root"><\/div>/);
  assert.match(html, /document\.querySelector\('meta\[name="theme-color"\]'\)\?\.setAttribute\("content", resolvedTheme === "dark" \? "#15171b" : "#f7f7f8"\)/);
});

test("native status-bar contrast follows the resolved app theme", async () => {
  const [provider, systemBars] = await Promise.all([
    readFile(new URL("./ThemeProvider.jsx", import.meta.url), "utf8"),
    readFile(new URL("../platform/system-bars.js", import.meta.url), "utf8").catch(() => "")
  ]);

  assert.match(systemBars, /theme === "dark" \? Style\.Dark : Style\.Light/);
  assert.match(provider, /syncSystemBars\(resolvedTheme\)/);
});

test("uses mode labels for explicit light and dark choices", () => {
  assert.equal(translate("en", "settings.dark"), "Dark mode");
  assert.equal(translate("en", "settings.light"), "Light mode");
  assert.equal(translate("ko", "settings.dark"), "다크 모드");
  assert.equal(translate("ko", "settings.light"), "라이트 모드");
});

test("light theme uses readable foreground colors without inversion", async () => {
  const css = await readFile(new URL("./styles/base.css", import.meta.url), "utf8");
  assert.match(css, /html\[data-theme="light"\] \.app-shell \*\{[^}]*color:#1f2328!important/s);
  assert.doesNotMatch(css, /html\[data-theme="light"\] \.app-shell\{filter:/);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.settings-overlay\{[^}]*background-color:rgba\(31,35,40,\.32\)!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.context-account-menu\{[^}]*background-color:#fff!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.context-reset-credit::before\{[^}]*background-color:#d8dee4!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.context-reset-credit button\{[^}]*background-color:transparent!important[^}]*color:#0969da!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.account-remove\{[^}]*border:0!important[^}]*color:#cf222e!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.settings-language-picker,html\[data-theme="light"\] \.app-shell \.settings-theme-picker,html\[data-theme="light"\] \.app-shell \.settings-language-trigger,html\[data-theme="light"\] \.app-shell \.settings-theme-trigger\{[^}]*background-color:transparent!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.account-login-dialog,html\[data-theme="light"\] \.app-shell \.settings-language-menu,html\[data-theme="light"\] \.app-shell \.settings-theme-menu\{[^}]*background-color:#fff!important/s);
});

test("light theme keeps active orange accents consistent with dark mode", async () => {
  const [baseCss, statusCss, chatsCss, conversationCss] = await Promise.all([
    readFile(new URL("./styles/base.css", import.meta.url), "utf8"),
    readFile(new URL("../features/status/status.css", import.meta.url), "utf8"),
    readFile(new URL("../features/chats/chats.css", import.meta.url), "utf8"),
    readFile(new URL("../features/conversation/conversation.css", import.meta.url), "utf8")
  ]);

  assert.match(chatsCss, /\.thread-status-dot--active\{[^}]*background:#f0a33a/s);
  assert.match(baseCss, /html\[data-theme="light"\] \.app-shell \.context-project-indicator--active\{[^}]*background:#f0a33a!important[^}]*background-color:#f0a33a!important/s);
  assert.match(baseCss, /html\[data-theme="light"\] \.app-shell \.activity-card\.waiting \.activity-state i\{[^}]*background:#f0a33a!important[^}]*background-color:#f0a33a!important/s);
  assert.match(baseCss, /html\[data-theme="light"\] \.usage-warning \.usage-percent\{[^}]*color:#f0a33a!important/s);
  assert.match(statusCss, /\.usage-warning \.usage-percent\{[^}]*color:#f0a33a/s);
  assert.match(statusCss, /html\[data-theme="light"\] \.app-shell \.usage-settings-limit\.usage-warning \.usage-settings-limit-value\{[^}]*color:#f0a33a!important/s);
  assert.match(statusCss, /html\[data-theme="light"\] \.app-shell \.usage-weekly-summary-card\.usage-warning \.usage-weekly-summary-value\{[^}]*color:#f0a33a!important/s);
  assert.match(conversationCss, /\.activity-card\.waiting \.activity-state i\{[^}]*background:#f0a33a/s);
});

test("light chat surfaces stay opaque while keeping composer controls compact", async () => {
  const [css, appCss, contextCss, conversationCss, notificationCss, changeSheetCss, chatsCss, projectPickerCss] = await Promise.all([
    readFile(new URL("./styles/base.css", import.meta.url), "utf8"),
    readFile(new URL("../app/app.css", import.meta.url), "utf8"),
    readFile(new URL("../features/context/context.css", import.meta.url), "utf8"),
    readFile(new URL("../features/conversation/conversation.css", import.meta.url), "utf8"),
    readFile(new URL("../features/notifications/notifications.css", import.meta.url), "utf8"),
    readFile(new URL("../features/changes/change-sheet.css", import.meta.url), "utf8"),
    readFile(new URL("../features/chats/chats.css", import.meta.url), "utf8"),
    readFile(new URL("../features/chats/project-picker.css", import.meta.url), "utf8")
  ]);

  assert.match(css, /html\[data-theme="light"\] \.app-shell \.composer-action-icon\{[^}]*background-color:#fff!important[^}]*box-shadow:0 1px 2px rgba\(31,35,40,\.12\)!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell \.composer-mic-icon\{[^}]*box-shadow:none!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell :is\(\.composer-send,\.composer-voice,\.composer-voice-stop\)\{[^}]*background-color:transparent!important[^}]*border:0!important[^}]*box-shadow:none!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell \.message-copy-popover\.is-open\{[^}]*background-color:transparent!important[^}]*border:0!important[^}]*box-shadow:none!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell \.message-copy-button\{[^}]*background-color:transparent!important[^}]*border:0!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell :is\(\.activity-file-direct-button,\.activity-file-group-button,\.activity-tool-call-button\)\{[^}]*background-color:transparent!important[^}]*border:0!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell :is\(\.change-sheet,\.tool-call-sheet\)\{[^}]*background-color:#fff!important/s);
  assert.match(css, /html\[data-theme="light"\] \.app-shell :is\(\.change-sheet-backdrop,\.tool-call-sheet-backdrop\)\{[^}]*background-color:rgba\(31,35,40,\.32\)!important/s);
  assert.doesNotMatch(css, /html\[data-theme="light"\] \.app-shell \*\{[^}]*background-color:transparent!important[^}]*box-shadow:none!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell \.message\.assistant\{[^}]*background-color:transparent!important[^}]*border:0!important[^}]*box-shadow:none!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell \.message\.user\{[^}]*background-color:#dbeafe!important[^}]*border-color:#93c5fd!important[^}]*box-shadow:none!important/s);
  assert.match(notificationCss, /\.notification-center-panel,html\[data-theme="light"\] \.app-shell \.notification-center-item\{[^}]*background-color:#fff!important/s);
  assert.match(changeSheetCss, /html\[data-theme="light"\] \.app-shell \.diff-fold\s*\{[^}]*background-color:\s*#f6f8fa\s*!important[^}]*color:\s*#57606a\s*!important/s);
  assert.match(chatsCss, /html\[data-theme="light"\] \.app-shell \.thread-state\s*\{[^}]*background-color:\s*transparent\s*!important[^}]*color:\s*#57606a\s*!important/s);
  assert.match(appCss, /html\[data-theme="light"\] \.app-shell \.status-connection-error\{[^}]*background-color:#fff1f2!important[^}]*color:#b4232d!important/s);
  assert.match(contextCss, /html\[data-theme="light"\] \.app-shell :is\(\.account-login-open,\.account-login-check\)\{[^}]*background-color:#fff!important/s);
  assert.match(projectPickerCss, /html\[data-theme="light"\] \.app-shell :is\(\.new-chat-panel,\.project-picker\)\{[^}]*background-color:#fff!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell \.approval-card\{[^}]*background-color:#fff8c5!important[^}]*color:#7a4b00!important/s);
  assert.match(conversationCss, /html\[data-theme="light"\] \.app-shell :is\(\.composer-voice-surface,\.queued-message,\.queued-message-popover,\.composer-attachment-preview\)\{[^}]*background-color:#fff!important/s);
});
