import { writable, derived } from "svelte/store";
import { invoke } from "@tauri-apps/api/core";
import { readFile } from "@tauri-apps/plugin-fs";

export type Theme =
  | "dark"
  | "light"
  | "high-contrast"
  | "custom"
  | "dracula"
  | "catppuccin"
  | "nord"
  | "solarized"
  | "solarized-light"
  | "catppuccin-latte"
  | "gruvbox-light"
  | "rose-pine-dawn";
export type BudgetAction = "warn" | "block";

export interface CustomThemeColors {
  bg_primary: string | null;
  bg_secondary: string | null;
  bg_terminal: string | null;
  accent_primary: string | null;
  accent_secondary: string | null;
  text_primary: string | null;
  text_secondary: string | null;
  border_color: string | null;
}

export interface HikariConfig {
  model: string | null;
  api_key: string | null;
  custom_instructions: string | null;
  mcp_servers_json: string | null;
  auto_granted_tools: string[];
  theme: Theme;
  greeting_enabled: boolean;
  greeting_custom_prompt: string | null;
  notifications_enabled: boolean;
  notification_volume: number;
  always_on_top: boolean;
  update_checks_enabled: boolean;
  character_panel_width: number | null;
  font_size: number;
  streamer_mode: boolean;
  streamer_hide_paths: boolean;
  compact_mode: boolean;
  profile_name: string | null;
  profile_avatar_path: string | null;
  profile_bio: string | null;
  custom_theme_colors: CustomThemeColors;
  // Budget settings
  budget_enabled: boolean;
  session_token_budget: number | null;
  session_cost_budget: number | null;
  budget_action: BudgetAction;
  budget_warning_threshold: number;
  // Discord RPC settings
  discord_rpc_enabled: boolean;
  // Thinking blocks settings
  show_thinking_blocks: boolean;
  // Worktree isolation
  use_worktree: boolean;
  // Disable 1M context window
  disable_1m_context: boolean;
  // Max output tokens for Claude Code responses
  max_output_tokens: number | null;
  // Workspaces the user has explicitly trusted
  trusted_workspaces: string[];
  // Background image settings
  background_image_path: string | null;
  background_image_opacity: number;
  // Custom terminal font settings
  custom_font_path: string | null;
  custom_font_family: string | null;
  // Custom UI font settings
  custom_ui_font_path: string | null;
  custom_ui_font_family: string | null;
  // Task Loop auto-commit settings
  task_loop_auto_commit: boolean;
  task_loop_commit_prefix: string;
  task_loop_include_summary: boolean;
}

const defaultConfig: HikariConfig = {
  model: null,
  api_key: null,
  custom_instructions: null,
  mcp_servers_json: null,
  auto_granted_tools: [],
  theme: "dark",
  greeting_enabled: true,
  greeting_custom_prompt: null,
  notifications_enabled: true,
  notification_volume: 0.7,
  always_on_top: false,
  update_checks_enabled: true,
  character_panel_width: null,
  font_size: 14,
  streamer_mode: false,
  streamer_hide_paths: false,
  compact_mode: false,
  profile_name: null,
  profile_avatar_path: null,
  profile_bio: null,
  custom_theme_colors: {
    bg_primary: null,
    bg_secondary: null,
    bg_terminal: null,
    accent_primary: null,
    accent_secondary: null,
    text_primary: null,
    text_secondary: null,
    border_color: null,
  },
  budget_enabled: false,
  session_token_budget: null,
  session_cost_budget: null,
  budget_action: "warn",
  budget_warning_threshold: 0.8,
  discord_rpc_enabled: true,
  show_thinking_blocks: true,
  use_worktree: false,
  disable_1m_context: false,
  max_output_tokens: null,
  trusted_workspaces: [],
  background_image_path: null,
  background_image_opacity: 0.3,
  custom_font_path: null,
  custom_font_family: null,
  custom_ui_font_path: null,
  custom_ui_font_family: null,
  task_loop_auto_commit: false,
  task_loop_commit_prefix: "feat",
  task_loop_include_summary: false,
};

function createConfigStore() {
  const config = writable<HikariConfig>(defaultConfig);
  const isLoading = writable<boolean>(true);
  const isSidebarOpen = writable<boolean>(false);
  const saveError = writable<string | null>(null);

  // Internal function to get current config synchronously
  function getCurrentConfig(): HikariConfig {
    let currentConfig: HikariConfig = defaultConfig;
    const unsubscribe = config.subscribe((c) => (currentConfig = c));
    unsubscribe();
    return currentConfig;
  }

  async function loadConfig() {
    isLoading.set(true);
    try {
      const savedConfig = await invoke<HikariConfig>("get_config");
      config.set(savedConfig);
    } catch (error) {
      console.error("Failed to load config:", error);
      config.set(defaultConfig);
    } finally {
      isLoading.set(false);
    }
  }

  async function saveConfig(newConfig: HikariConfig) {
    saveError.set(null);
    try {
      await invoke("save_config", { config: newConfig });
      config.set(newConfig);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      saveError.set(errorMessage);
      console.error("Failed to save config:", error);
      throw error;
    }
  }

  async function updateConfig(updates: Partial<HikariConfig>) {
    const currentConfig = getCurrentConfig();
    const newConfig = { ...currentConfig, ...updates };
    await saveConfig(newConfig);
  }

  return {
    config: { subscribe: config.subscribe },
    isLoading: { subscribe: isLoading.subscribe },
    isSidebarOpen: { subscribe: isSidebarOpen.subscribe },
    saveError: { subscribe: saveError.subscribe },

    loadConfig,
    saveConfig,
    updateConfig,

    openSidebar: () => isSidebarOpen.set(true),
    closeSidebar: () => isSidebarOpen.set(false),
    toggleSidebar: () => isSidebarOpen.update((open) => !open),

    setTheme: async (theme: Theme, customColors?: CustomThemeColors) => {
      const updates: Partial<HikariConfig> = { theme };
      if (customColors) {
        updates.custom_theme_colors = customColors;
      }
      await updateConfig(updates);
      const currentConfig = getCurrentConfig();
      applyTheme(theme, currentConfig.custom_theme_colors);
    },

    setCustomThemeColors: async (colors: CustomThemeColors) => {
      await updateConfig({ custom_theme_colors: colors });
      const currentConfig = getCurrentConfig();
      if (currentConfig.theme === "custom") {
        applyCustomThemeColors(colors);
      }
    },

    setFontSize: async (size: number) => {
      const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size));
      await updateConfig({ font_size: clampedSize });
      applyFontSize(clampedSize);
    },

    increaseFontSize: async () => {
      const currentConfig = getCurrentConfig();
      const newSize = Math.min(MAX_FONT_SIZE, currentConfig.font_size + 2);
      await updateConfig({ font_size: newSize });
      applyFontSize(newSize);
    },

    decreaseFontSize: async () => {
      const currentConfig = getCurrentConfig();
      const newSize = Math.max(MIN_FONT_SIZE, currentConfig.font_size - 2);
      await updateConfig({ font_size: newSize });
      applyFontSize(newSize);
    },

    resetFontSize: async () => {
      await updateConfig({ font_size: DEFAULT_FONT_SIZE });
      applyFontSize(DEFAULT_FONT_SIZE);
    },

    addAutoGrantedTool: async (tool: string) => {
      const currentConfig = getCurrentConfig();
      if (!currentConfig.auto_granted_tools.includes(tool)) {
        const newTools = [...currentConfig.auto_granted_tools, tool];
        await updateConfig({ auto_granted_tools: newTools });
      }
    },

    removeAutoGrantedTool: async (tool: string) => {
      const currentConfig = getCurrentConfig();
      const newTools = currentConfig.auto_granted_tools.filter((t) => t !== tool);
      await updateConfig({ auto_granted_tools: newTools });
    },

    getConfig: (): HikariConfig => {
      return getCurrentConfig();
    },

    toggleStreamerMode: async () => {
      const currentConfig = getCurrentConfig();
      await updateConfig({ streamer_mode: !currentConfig.streamer_mode });
    },

    toggleCompactMode: async () => {
      const currentConfig = getCurrentConfig();
      await updateConfig({ compact_mode: !currentConfig.compact_mode });
    },

    setCompactMode: async (enabled: boolean) => {
      await updateConfig({ compact_mode: enabled });
    },

    setCustomFont: async (path: string | null, family: string | null) => {
      await updateConfig({ custom_font_path: path, custom_font_family: family });
      await applyCustomFont(path, family);
    },

    setCustomUiFont: async (path: string | null, family: string | null) => {
      await updateConfig({ custom_ui_font_path: path, custom_ui_font_family: family });
      await applyCustomUiFont(path, family);
    },
  };
}

export function applyTheme(theme: Theme, customColors?: CustomThemeColors) {
  if (typeof document !== "undefined") {
    // For custom theme, we use dark as the base and override with custom colors
    document.documentElement.setAttribute("data-theme", theme === "custom" ? "dark" : theme);

    // Clear any previously applied custom colors
    clearCustomThemeColors();

    // Apply custom colors if theme is custom
    if (theme === "custom" && customColors) {
      applyCustomThemeColors(customColors);
    }
  }
}

export function applyCustomThemeColors(colors: CustomThemeColors) {
  if (typeof document === "undefined") return;

  const root = document.documentElement;
  if (colors.bg_primary) root.style.setProperty("--bg-primary", colors.bg_primary);
  if (colors.bg_secondary) root.style.setProperty("--bg-secondary", colors.bg_secondary);
  if (colors.bg_terminal) root.style.setProperty("--bg-terminal", colors.bg_terminal);
  if (colors.accent_primary) root.style.setProperty("--accent-primary", colors.accent_primary);
  if (colors.accent_secondary)
    root.style.setProperty("--accent-secondary", colors.accent_secondary);
  if (colors.text_primary) root.style.setProperty("--text-primary", colors.text_primary);
  if (colors.text_secondary) root.style.setProperty("--text-secondary", colors.text_secondary);
  if (colors.border_color) root.style.setProperty("--border-color", colors.border_color);
}

export function clearCustomThemeColors() {
  if (typeof document === "undefined") return;

  const root = document.documentElement;
  const customProperties = [
    "--bg-primary",
    "--bg-secondary",
    "--bg-terminal",
    "--accent-primary",
    "--accent-secondary",
    "--text-primary",
    "--text-secondary",
    "--border-color",
  ];
  customProperties.forEach((prop) => root.style.removeProperty(prop));
}

const MIN_FONT_SIZE = 10;
const MAX_FONT_SIZE = 24;
const DEFAULT_FONT_SIZE = 14;

export function applyFontSize(size: number) {
  if (typeof document !== "undefined") {
    const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size));
    document.documentElement.style.setProperty("--terminal-font-size", `${clampedSize}px`);
  }
}

export function clampFontSize(size: number): number {
  return Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size));
}

const DIRECT_FONT_EXTENSIONS = new Set(["woff", "woff2", "ttf", "otf", "eot"]);

const FONT_MIME_MAP: Record<string, string> = {
  woff: "font/woff",
  woff2: "font/woff2",
  ttf: "font/ttf",
  otf: "font/otf",
  eot: "application/vnd.ms-fontobject",
};

async function applyFontFromSource(path: string, family: string, styleId: string): Promise<void> {
  const style = document.createElement("style");
  style.id = styleId;

  if (path.startsWith("http://") || path.startsWith("https://")) {
    const ext = path.split(".").pop()?.toLowerCase() ?? "";

    if (DIRECT_FONT_EXTENSIONS.has(ext)) {
      style.textContent = `@font-face { font-family: '${family}'; src: url('${path}'); }`;
    } else {
      style.textContent = `@import url('${path}');`;
    }
  } else {
    const data = await readFile(path);
    const chunks: string[] = [];
    const chunkSize = 8192;
    for (let i = 0; i < data.length; i += chunkSize) {
      chunks.push(String.fromCharCode(...data.slice(i, i + chunkSize)));
    }
    const ext = path.split(".").pop()?.toLowerCase() ?? "ttf";
    const mime = FONT_MIME_MAP[ext] ?? "font/ttf";
    const dataUrl = `data:${mime};base64,${btoa(chunks.join(""))}`;
    style.textContent = `@font-face { font-family: '${family}'; src: url('${dataUrl}'); }`;
  }

  document.head.appendChild(style);
}

export async function applyCustomFont(path: string | null, family: string | null): Promise<void> {
  if (typeof document === "undefined") return;

  const styleId = "hikari-custom-font";
  const cssVar = "--terminal-font-family";
  const fallbackFamily = "HikariCustomFont";

  document.getElementById(styleId)?.remove();

  const trimmedPath = path?.trim() ?? "";
  const trimmedFamily = family?.trim() ?? "";

  if (!trimmedPath && !trimmedFamily) {
    document.documentElement.style.removeProperty(cssVar);
    return;
  }

  if (trimmedPath) {
    await applyFontFromSource(trimmedPath, trimmedFamily || fallbackFamily, styleId);
  }

  if (trimmedFamily) {
    document.documentElement.style.setProperty(cssVar, `'${trimmedFamily}', monospace`);
  }
}

export async function applyCustomUiFont(path: string | null, family: string | null): Promise<void> {
  if (typeof document === "undefined") return;

  const styleId = "hikari-custom-ui-font";
  const cssVar = "--ui-font-family";
  const fallbackFamily = "HikariCustomUiFont";

  document.getElementById(styleId)?.remove();

  const trimmedPath = path?.trim() ?? "";
  const trimmedFamily = family?.trim() ?? "";

  if (!trimmedPath && !trimmedFamily) {
    document.documentElement.style.removeProperty(cssVar);
    document.body?.style.removeProperty("font-family");
    return;
  }

  const effectiveFamily = trimmedFamily || fallbackFamily;

  if (trimmedPath) {
    await applyFontFromSource(trimmedPath, effectiveFamily, styleId);
  }

  const fontValue = `'${effectiveFamily}', sans-serif`;
  document.documentElement.style.setProperty(cssVar, fontValue);
  document.body?.style.setProperty("font-family", fontValue);
}

export { MIN_FONT_SIZE, MAX_FONT_SIZE, DEFAULT_FONT_SIZE };

export const configStore = createConfigStore();

export const isDarkTheme = derived(configStore.config, ($config) => $config.theme === "dark");

export const isStreamerMode = derived(configStore.config, ($config) => $config.streamer_mode);
export const isCompactMode = derived(configStore.config, ($config) => $config.compact_mode);
export const shouldHidePaths = derived(
  configStore.config,
  ($config) => $config.streamer_mode && $config.streamer_hide_paths
);
export const showThinkingBlocks = derived(
  configStore.config,
  ($config) => $config.show_thinking_blocks
);

/**
 * Masks file paths in text when streamer mode with hide paths is enabled.
 * Replaces username portion of paths with asterisks.
 */
export function maskPaths(text: string, hidePaths: boolean): string {
  if (!hidePaths) return text;

  // Match Unix paths like /home/username/... or /Users/username/...
  // and Windows paths like C:\Users\username\...
  return text
    .replace(/\/home\/([^/\s]+)/g, "/home/****")
    .replace(/\/Users\/([^/\s]+)/g, "/Users/****")
    .replace(/C:\\Users\\([^\\\s]+)/gi, "C:\\Users\\****")
    .replace(/~\//g, "****/");
}
