/**
 * Appearance Preferences Module
 *
 * Manages accent color, typography, and icon set preferences with localStorage persistence.
 */

import { ICON_SETS, getIconSvgInner } from '../icons/index'
import type { IconSet } from '../icons/index'
import { configureTheme } from '../ui/index'
import type { ResolvedTheme } from '../ui/index'

export { ICON_SETS, getIconSvgInner }
export type { IconSet }
export type AccentTheme = 'orange' | 'cyan' | 'violet' | 'rose' | 'emerald'
export type FontPreference = 'sora' | 'inter' | 'roboto' | 'system' | 'jetbrains-mono'

export interface AppearanceConfig {
  onToggleCycleUpdate?: (themes: ResolvedTheme[]) => void
}

export interface AppearanceSyncConfig extends AppearanceConfig {
  endpoint?: string
  getToken?: () => string | null
}

const ACCENT_KEY = 'accent_theme'
const FONT_KEY = 'typography'
const ICON_SET_KEY = 'icon_set'
const QUICK_SWITCHER_KEY = 'quick_switcher_themes'

const ALL_RESOLVED_THEMES: ResolvedTheme[] = ['light', 'dark', 'monokai', 'glass']

const VALID_ACCENTS: AccentTheme[] = ['orange', 'cyan', 'violet', 'rose', 'emerald']
const VALID_FONTS: FontPreference[] = ['sora', 'inter', 'roboto', 'system', 'jetbrains-mono']
const VALID_ICON_SETS: IconSet[] = ['lucide', 'heroicons', 'phosphor', 'material']

const DEFAULT_ENDPOINT = '/api/v1/users/me/appearance'

export function isValidAccent(value: string | null | undefined): value is AccentTheme {
  return typeof value === 'string' && VALID_ACCENTS.includes(value as AccentTheme)
}

export function isValidFont(value: string | null | undefined): value is FontPreference {
  return typeof value === 'string' && VALID_FONTS.includes(value as FontPreference)
}

export function getStoredAccent(): AccentTheme {
  const stored = localStorage.getItem(ACCENT_KEY)
  return isValidAccent(stored) ? stored : 'orange'
}

export function getStoredFont(): FontPreference {
  const stored = localStorage.getItem(FONT_KEY)
  return isValidFont(stored) ? stored : 'sora'
}

export function applyAccent(accent: AccentTheme): void {
  if (accent === 'orange') {
    document.documentElement.removeAttribute('data-accent')
  } else {
    document.documentElement.setAttribute('data-accent', accent)
  }
}

export function applyFont(font: FontPreference): void {
  if (font === 'sora') {
    document.documentElement.removeAttribute('data-font')
  } else {
    document.documentElement.setAttribute('data-font', font)
  }
}

export function setAccent(accent: AccentTheme): void {
  localStorage.setItem(ACCENT_KEY, accent)
  applyAccent(accent)
}

export function setFont(font: FontPreference): void {
  localStorage.setItem(FONT_KEY, font)
  applyFont(font)
}

export function isValidIconSet(value: string | null | undefined): value is IconSet {
  return typeof value === 'string' && VALID_ICON_SETS.includes(value as IconSet)
}

export function getStoredIconSet(): IconSet {
  const stored = localStorage.getItem(ICON_SET_KEY)
  return isValidIconSet(stored) ? stored : 'lucide'
}

export function applyIconSet(iconSet: IconSet): void {
  const icons = document.querySelectorAll<SVGElement>('[data-icon]')
  for (const el of icons) {
    const name = el.getAttribute('data-icon')
    if (name === null || name.length === 0) {
      continue
    }
    const inner = getIconSvgInner(iconSet, name)
    if (inner !== undefined) {
      el.innerHTML = inner
    }
  }
  if (iconSet === 'lucide') {
    document.documentElement.removeAttribute('data-icon-set')
  } else {
    document.documentElement.setAttribute('data-icon-set', iconSet)
  }
}

export function setIconSet(iconSet: IconSet): void {
  localStorage.setItem(ICON_SET_KEY, iconSet)
  applyIconSet(iconSet)
}

export function getStoredQuickSwitcherThemes(): ResolvedTheme[] {
  const stored = localStorage.getItem(QUICK_SWITCHER_KEY)
  if (stored === null || stored.length === 0) {
    return [...ALL_RESOLVED_THEMES]
  }
  try {
    const parsed = JSON.parse(stored) as string[]
    const valid = parsed.filter(t =>
      ALL_RESOLVED_THEMES.includes(t as ResolvedTheme)
    ) as ResolvedTheme[]
    return valid.length > 0 ? valid : [...ALL_RESOLVED_THEMES]
  } catch {
    return [...ALL_RESOLVED_THEMES]
  }
}

export function setQuickSwitcherThemes(themes: ResolvedTheme[]): void {
  localStorage.setItem(QUICK_SWITCHER_KEY, JSON.stringify(themes))
}

export function initAppearance(config?: AppearanceConfig): void {
  applyAccent(getStoredAccent())
  applyFont(getStoredFont())
  applyIconSet(getStoredIconSet())
  const themes = getStoredQuickSwitcherThemes()
  if (config?.onToggleCycleUpdate) {
    config.onToggleCycleUpdate(themes)
  }
}

interface ServerAppearanceResponse {
  accent?: string
  font?: string
  icon_set?: string
}

/**
 * Fetch server-side appearance preferences and apply them locally.
 * Call this after DOMContentLoaded when an auth token is available.
 */
export async function syncAppearanceFromServer(config?: AppearanceSyncConfig): Promise<void> {
  const endpoint = config?.endpoint ?? DEFAULT_ENDPOINT
  const token = config?.getToken ? config.getToken() : null

  const headers: Record<string, string> = {}
  if (token) {
    headers.Authorization = `Bearer ${token}`
  }

  let data: ServerAppearanceResponse
  try {
    const res = await fetch(endpoint, { headers })
    if (!res.ok) {
      return
    }
    data = (await res.json()) as ServerAppearanceResponse
  } catch {
    return
  }

  if (isValidAccent(data.accent) && data.accent !== getStoredAccent()) {
    setAccent(data.accent)
  }

  if (isValidFont(data.font) && data.font !== getStoredFont()) {
    setFont(data.font)
  }

  if (isValidIconSet(data.icon_set) && data.icon_set !== getStoredIconSet()) {
    setIconSet(data.icon_set)
  }

  if (config?.onToggleCycleUpdate) {
    const themes = getStoredQuickSwitcherThemes()
    configureTheme({ themes })
    config.onToggleCycleUpdate(themes)
  }
}
