import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from "react";

/* Theme definitions — mirrors @dangerousthings/tokens types */
export interface ThemeDefinition {
  id: string;
  name: string;
  description: string;
  supportsModes: ThemeMode[];
  defaultMode: ThemeMode;
  author?: string;
  css_url?: string;
  source?: "builtin" | "plugin";
}

export type ThemeBrand = string; // dynamic — supports plugin themes beyond dt/classic/supra
export type ThemeMode = "dark" | "light" | "auto";

/** Hardcoded fallback themes for SSR / offline / initial render */
export const builtinThemes: ThemeDefinition[] = [
  {
    id: "dt",
    name: "Dangerous Things",
    description: "Official DT brand \u2014 Tektur font, neon cyberpunk, beveled corners",
    supportsModes: ["dark", "light", "auto"],
    defaultMode: "dark",
  },
  {
    id: "classic",
    name: "Classic Cyberpunk",
    description: "Original dark navy aesthetic with magenta accents",
    supportsModes: ["dark", "light", "auto"],
    defaultMode: "dark",
  },
  {
    id: "supra",
    name: "VivoKey Supra",
    description: "Material Design 3 with VivoKey blue, rounded corners, elevation shadows",
    supportsModes: ["dark", "light", "auto"],
    defaultMode: "dark",
  },
];

/** @deprecated Use builtinThemes instead */
export const themes = builtinThemes;

export const DEFAULT_THEME: ThemeBrand = "dt";

const BRAND_STORAGE_KEY = "dpi_theme_brand";
const MODE_STORAGE_KEY = "theme"; // backward compatible with existing key

interface ThemeContextValue {
  brand: ThemeBrand;
  mode: ThemeMode;
  setBrand: (brand: ThemeBrand) => void;
  setMode: (mode: ThemeMode) => void;
  themeDefinition: ThemeDefinition;
  availableThemes: ThemeDefinition[];
}

const ThemeContext = createContext<ThemeContextValue | null>(null);

/**
 * Inject or update a <link> element for a theme's dynamic token CSS.
 * Identified by a fixed id so it can be swapped in place.
 */
function setTokenStylesheet(url: string | undefined) {
  if (typeof document === "undefined") return;

  const LINK_ID = "dp-theme-tokens";
  let link = document.getElementById(LINK_ID) as HTMLLinkElement | null;

  if (!url) {
    link?.remove();
    return;
  }

  if (link) {
    if (link.getAttribute("href") !== url) {
      link.setAttribute("href", url);
    }
  } else {
    link = document.createElement("link");
    link.id = LINK_ID;
    link.rel = "stylesheet";
    link.href = url;
    document.head.appendChild(link);
  }
}

export function ThemeProvider({ children }: { children: ReactNode }) {
  const [brand, setBrandState] = useState<ThemeBrand>(() => {
    if (typeof window === "undefined") return DEFAULT_THEME;
    return localStorage.getItem(BRAND_STORAGE_KEY) || DEFAULT_THEME;
  });

  const [mode, setModeState] = useState<ThemeMode>(() => {
    if (typeof window === "undefined") return "dark";
    return (localStorage.getItem(MODE_STORAGE_KEY) as ThemeMode) || "dark";
  });

  const [availableThemes, setAvailableThemes] = useState<ThemeDefinition[]>(builtinThemes);

  // Fetch dynamic theme list from API on mount
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const resp = await fetch("/api/system/themes");
        if (!resp.ok) return;
        const data = await resp.json();
        if (!cancelled && Array.isArray(data.themes) && data.themes.length > 0) {
          setAvailableThemes(data.themes);
        }
      } catch {
        // API unavailable — keep fallback themes
      }
    })();
    return () => { cancelled = true; };
  }, []);

  const setBrand = useCallback((newBrand: ThemeBrand) => {
    setBrandState(newBrand);
    localStorage.setItem(BRAND_STORAGE_KEY, newBrand);
    document.documentElement.setAttribute("data-brand", newBrand);
  }, []);

  const setMode = useCallback((newMode: ThemeMode) => {
    setModeState(newMode);
    localStorage.setItem(MODE_STORAGE_KEY, newMode);
    document.documentElement.setAttribute("data-theme", newMode);
  }, []);

  // Set DOM attributes + inject token stylesheet when brand/mode/themes change
  useEffect(() => {
    document.documentElement.setAttribute("data-brand", brand);
    document.documentElement.setAttribute("data-theme", mode);

    const def = availableThemes.find((t) => t.id === brand);
    setTokenStylesheet(def?.css_url);
  }, [brand, mode, availableThemes]);

  const themeDefinition = availableThemes.find((t) => t.id === brand) || availableThemes[0] || builtinThemes[0];

  return (
    <ThemeContext.Provider value={{ brand, mode, setBrand, setMode, themeDefinition, availableThemes }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme(): ThemeContextValue {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
  return ctx;
}
