import fs from "node:fs";
import path from "node:path";
import {
  DEFAULT_OPENCLAW_BROWSER_COLOR,
  DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME,
} from "./constants.js";

function decoratedMarkerPath(userDataDir: string) {
  return path.join(userDataDir, ".openclaw-profile-decorated");
}

function safeReadJson(filePath: string): Record<string, unknown> | null {
  try {
    if (!fs.existsSync(filePath)) {
      return null;
    }
    const raw = fs.readFileSync(filePath, "utf-8");
    const parsed = JSON.parse(raw) as unknown;
    if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
      return null;
    }
    return parsed as Record<string, unknown>;
  } catch {
    return null;
  }
}

function safeWriteJson(filePath: string, data: Record<string, unknown>) {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
}

function setDeep(obj: Record<string, unknown>, keys: string[], value: unknown) {
  let node: Record<string, unknown> = obj;
  for (const key of keys.slice(0, -1)) {
    const next = node[key];
    if (typeof next !== "object" || next === null || Array.isArray(next)) {
      node[key] = {};
    }
    node = node[key] as Record<string, unknown>;
  }
  node[keys[keys.length - 1] ?? ""] = value;
}

function parseHexRgbToSignedArgbInt(hex: string): number | null {
  const cleaned = hex.trim().replace(/^#/, "");
  if (!/^[0-9a-fA-F]{6}$/.test(cleaned)) {
    return null;
  }
  const rgb = Number.parseInt(cleaned, 16);
  const argbUnsigned = (0xff << 24) | rgb;
  // Chrome stores colors as signed 32-bit ints (SkColor).
  return argbUnsigned > 0x7fffffff ? argbUnsigned - 0x1_0000_0000 : argbUnsigned;
}

export function isProfileDecorated(
  userDataDir: string,
  desiredName: string,
  desiredColorHex: string,
): boolean {
  const desiredColorInt = parseHexRgbToSignedArgbInt(desiredColorHex);

  const localStatePath = path.join(userDataDir, "Local State");
  const preferencesPath = path.join(userDataDir, "Default", "Preferences");

  const localState = safeReadJson(localStatePath);
  const profile = localState?.profile;
  const infoCache =
    typeof profile === "object" && profile !== null && !Array.isArray(profile)
      ? (profile as Record<string, unknown>).info_cache
      : null;
  const info =
    typeof infoCache === "object" &&
    infoCache !== null &&
    !Array.isArray(infoCache) &&
    typeof (infoCache as Record<string, unknown>).Default === "object" &&
    (infoCache as Record<string, unknown>).Default !== null &&
    !Array.isArray((infoCache as Record<string, unknown>).Default)
      ? ((infoCache as Record<string, unknown>).Default as Record<string, unknown>)
      : null;

  const prefs = safeReadJson(preferencesPath);
  const browserTheme = (() => {
    const browser = prefs?.browser;
    const theme =
      typeof browser === "object" && browser !== null && !Array.isArray(browser)
        ? (browser as Record<string, unknown>).theme
        : null;
    return typeof theme === "object" && theme !== null && !Array.isArray(theme)
      ? (theme as Record<string, unknown>)
      : null;
  })();

  const autogeneratedTheme = (() => {
    const autogenerated = prefs?.autogenerated;
    const theme =
      typeof autogenerated === "object" && autogenerated !== null && !Array.isArray(autogenerated)
        ? (autogenerated as Record<string, unknown>).theme
        : null;
    return typeof theme === "object" && theme !== null && !Array.isArray(theme)
      ? (theme as Record<string, unknown>)
      : null;
  })();

  const nameOk = typeof info?.name === "string" ? info.name === desiredName : true;

  if (desiredColorInt == null) {
    // If the user provided a non-#RRGGBB value, we can only do best-effort.
    return nameOk;
  }

  const localSeedOk =
    typeof info?.profile_color_seed === "number"
      ? info.profile_color_seed === desiredColorInt
      : false;

  const prefOk =
    (typeof browserTheme?.user_color2 === "number" &&
      browserTheme.user_color2 === desiredColorInt) ||
    (typeof autogeneratedTheme?.color === "number" && autogeneratedTheme.color === desiredColorInt);

  return nameOk && localSeedOk && prefOk;
}

/**
 * Best-effort profile decoration (name + lobster-orange). Chrome preference keys
 * vary by version; we keep this conservative and idempotent.
 */
export function decorateOpenClawProfile(
  userDataDir: string,
  opts?: { name?: string; color?: string },
) {
  const desiredName = opts?.name ?? DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME;
  const desiredColor = (opts?.color ?? DEFAULT_OPENCLAW_BROWSER_COLOR).toUpperCase();
  const desiredColorInt = parseHexRgbToSignedArgbInt(desiredColor);

  const localStatePath = path.join(userDataDir, "Local State");
  const preferencesPath = path.join(userDataDir, "Default", "Preferences");

  const localState = safeReadJson(localStatePath) ?? {};
  // Common-ish shape: profile.info_cache.Default
  setDeep(localState, ["profile", "info_cache", "Default", "name"], desiredName);
  setDeep(localState, ["profile", "info_cache", "Default", "shortcut_name"], desiredName);
  setDeep(localState, ["profile", "info_cache", "Default", "user_name"], desiredName);
  // Color keys are best-effort (Chrome changes these frequently).
  setDeep(localState, ["profile", "info_cache", "Default", "profile_color"], desiredColor);
  setDeep(localState, ["profile", "info_cache", "Default", "user_color"], desiredColor);
  if (desiredColorInt != null) {
    // These are the fields Chrome actually uses for profile/avatar tinting.
    setDeep(
      localState,
      ["profile", "info_cache", "Default", "profile_color_seed"],
      desiredColorInt,
    );
    setDeep(
      localState,
      ["profile", "info_cache", "Default", "profile_highlight_color"],
      desiredColorInt,
    );
    setDeep(
      localState,
      ["profile", "info_cache", "Default", "default_avatar_fill_color"],
      desiredColorInt,
    );
    setDeep(
      localState,
      ["profile", "info_cache", "Default", "default_avatar_stroke_color"],
      desiredColorInt,
    );
  }
  safeWriteJson(localStatePath, localState);

  const prefs = safeReadJson(preferencesPath) ?? {};
  setDeep(prefs, ["profile", "name"], desiredName);
  setDeep(prefs, ["profile", "profile_color"], desiredColor);
  setDeep(prefs, ["profile", "user_color"], desiredColor);
  if (desiredColorInt != null) {
    // Chrome refresh stores the autogenerated theme in these prefs (SkColor ints).
    setDeep(prefs, ["autogenerated", "theme", "color"], desiredColorInt);
    // User-selected browser theme color (pref name: browser.theme.user_color2).
    setDeep(prefs, ["browser", "theme", "user_color2"], desiredColorInt);
  }
  safeWriteJson(preferencesPath, prefs);

  try {
    fs.writeFileSync(decoratedMarkerPath(userDataDir), `${Date.now()}\n`, "utf-8");
  } catch {
    // ignore
  }
}

export function ensureProfileCleanExit(userDataDir: string) {
  const preferencesPath = path.join(userDataDir, "Default", "Preferences");
  const prefs = safeReadJson(preferencesPath) ?? {};
  setDeep(prefs, ["exit_type"], "Normal");
  setDeep(prefs, ["exited_cleanly"], true);
  safeWriteJson(preferencesPath, prefs);
}
