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

export type Theme = "dark" | "light" | "high-contrast" | "custom";

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;
  minimize_to_tray: 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;
}

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,
  minimize_to_tray: 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,
  },
};

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

  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>) {
    let currentConfig: HikariConfig = defaultConfig;
    config.subscribe((c) => (currentConfig = c))();
    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);
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      applyTheme(theme, currentConfig.custom_theme_colors);
    },

    setCustomThemeColors: async (colors: CustomThemeColors) => {
      await updateConfig({ custom_theme_colors: colors });
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      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 () => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      const newSize = Math.min(MAX_FONT_SIZE, currentConfig.font_size + 2);
      await updateConfig({ font_size: newSize });
      applyFontSize(newSize);
    },

    decreaseFontSize: async () => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      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) => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      if (!currentConfig.auto_granted_tools.includes(tool)) {
        const newTools = [...currentConfig.auto_granted_tools, tool];
        await updateConfig({ auto_granted_tools: newTools });
      }
    },

    removeAutoGrantedTool: async (tool: string) => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      const newTools = currentConfig.auto_granted_tools.filter((t) => t !== tool);
      await updateConfig({ auto_granted_tools: newTools });
    },

    getConfig: (): HikariConfig => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      return currentConfig;
    },

    toggleStreamerMode: async () => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      await updateConfig({ streamer_mode: !currentConfig.streamer_mode });
    },

    toggleCompactMode: async () => {
      let currentConfig: HikariConfig = defaultConfig;
      config.subscribe((c) => (currentConfig = c))();
      await updateConfig({ compact_mode: !currentConfig.compact_mode });
    },

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

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));
}

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
);

/**
 * 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, "****/");
}
