import { useState, useEffect, useCallback, type ComponentType, type ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { AlertCircle, Moon, Monitor, RefreshCw, Sun, Users, HelpCircle } from 'lucide-react';
import { api } from '@/api';
import { cn, errMessage, settingEnabled, setDateFormat } from '@/lib/utils';
import { setMoneyFormat } from '@/lib/money';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { CalendarFeedManager } from '@/components/CalendarFeedManager';
import {
  Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { useTheme } from '@/contexts/ThemeContext';
import { useMotionPreference } from '@/contexts/MotionPreferenceContext';
import { useAuth } from '@/hooks/useAuth';
import { useAutoSave } from '@/hooks/useAutoSave';
import { SaveStatus } from '@/components/ui/save-status';
import { NotificationPreferences, PushNotifications, asSettings } from '@/pages/ProfilePage';

export const LINK_IMPORT_PREF_KEY = 'link_import_ask';
export function getLinkImportPref(): boolean {
  return localStorage.getItem(LINK_IMPORT_PREF_KEY) !== 'false';
}

// ─── Notifications (moved here from Profile — these are app-behavior
//     preferences; Profile keeps identity, security, and privacy) ──────────────

function NotificationsSection() {
  const [settings, setSettings] = useState<Record<string, unknown> | null>(null);

  const load = useCallback(() => {
    api.profileSettings()
      .then((data) => setSettings(asSettings(data)))
      .catch((err) => toast.error(errMessage(err, 'Failed to load notification settings.')));
  }, []);

  useEffect(() => { load(); }, [load]);

  if (!settings) return null;
  return (
    <div className="space-y-4 mb-4">
      <NotificationPreferences settings={settings} />
      <PushNotifications settings={settings} onSaved={load} />
    </div>
  );
}

// ─── Card wrapper ─────────────────────────────────────────────────────────────

function SectionCard({ title, children }: { title: ReactNode; children: ReactNode }) {
  return (
    <div className="table-surface mb-4">
      <div className="px-6 py-4 border-b border-border/50">
        <h2 className="text-xs font-bold uppercase tracking-widest text-muted-foreground">{title}</h2>
      </div>
      <div className="divide-y divide-border/50">
        {children}
      </div>
    </div>
  );
}

// ─── Setting Row ──────────────────────────────────────────────────────────────

function SettingRow({ label, description, children }: { label: ReactNode; description?: ReactNode; children: ReactNode }) {
  return (
    <div className="px-4 py-4 flex flex-col gap-3 sm:px-6 sm:flex-row sm:items-center sm:justify-between">
      <div className="flex-1 min-w-0 sm:mr-8">
        <p className="text-sm font-medium">{label}</p>
        {description && (
          <p className="text-xs text-muted-foreground mt-0.5">{description}</p>
        )}
      </div>
      <div className="shrink-0">
        {children}
      </div>
    </div>
  );
}

// ─── Inline help tooltip ──────────────────────────────────────────────────────
// A focusable help icon that explains a non-obvious setting. Sits next to a
// SettingRow label. Keyboard + screen-reader accessible (button + aria-label).

function SettingHelp({ text, label }: { text: string; label: string }) {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <button
          type="button"
          aria-label={`${label}: help`}
          className="ml-1.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
        >
          <HelpCircle className="h-3.5 w-3.5" />
        </button>
      </TooltipTrigger>
      <TooltipContent className="max-w-[260px] text-xs leading-relaxed">{text}</TooltipContent>
    </Tooltip>
  );
}

// ─── Theme Card ───────────────────────────────────────────────────────────────

function ThemeCard({ value, label, icon: Icon, currentTheme, onSelect }: {
  value: string;
  label: string;
  icon: ComponentType<{ className?: string }>;
  currentTheme: string;
  onSelect: (v: string) => void;
}) {
  const selected = currentTheme === value;
  return (
    <button
      type="button"
      onClick={() => onSelect(value)}
      className={cn(
        'flex flex-col items-center gap-1.5 rounded-lg border px-3 py-2.5 text-xs font-medium transition-all',
        'hover:border-muted-foreground/50',
        selected
          ? 'border-primary bg-primary/5 text-primary'
          : 'border-border bg-card text-muted-foreground',
      )}
    >
      <Icon className="h-4 w-4" />
      <span>{label}</span>
    </button>
  );
}

// ─── Appearance Section ───────────────────────────────────────────────────────

function AppearanceSection() {
  const { theme, setTheme } = useTheme();
  const { reduceMotion, setReduceMotion } = useMotionPreference();

  return (
    <SectionCard title="Appearance">
      <SettingRow
        label={<span className="inline-flex items-center">Theme<SettingHelp label="Theme" text="“System” follows your device's light/dark setting and switches automatically when it changes." /></span>}
        description="Choose your preferred color scheme."
      >
        <div className="flex gap-2">
          <ThemeCard value="light"  label="Light"  icon={Sun}     currentTheme={theme} onSelect={setTheme} />
          <ThemeCard value="dark"   label="Dark"   icon={Moon}    currentTheme={theme} onSelect={setTheme} />
          <ThemeCard value="system" label="System" icon={Monitor} currentTheme={theme} onSelect={setTheme} />
        </div>
      </SettingRow>
      <SettingRow
        label={<span className="inline-flex items-center">Reduce motion<SettingHelp label="Reduce motion" text="Turns off animations and transitions across the app. Also respects your device's reduced-motion setting." /></span>}
        description="Minimize animations and transitions."
      >
        <Switch
          checked={reduceMotion}
          onCheckedChange={setReduceMotion}
          aria-label="Reduce motion"
        />
      </SettingRow>
    </SectionCard>
  );
}

function LoginModeRecoverySection() {
  const navigate = useNavigate();
  const { singleUserMode, refresh } = useAuth();
  const [restoring, setRestoring] = useState(false);

  if (!singleUserMode) return null;

  const handleRestore = async () => {
    setRestoring(true);
    try {
      await api.restoreMultiUserMode();
      toast.success('Multi-user login restored.');
      refresh();
      navigate('/login', { replace: true });
    } catch (err) {
      toast.error(errMessage(err, 'Failed to restore multi-user mode.'));
    } finally {
      setRestoring(false);
    }
  };

  return (
    <SectionCard title="Login Mode">
      <SettingRow
        label="Single-user mode is active"
        description="Restore the normal login screen so each user signs in with their own account."
      >
        <Button size="sm" variant="outline" onClick={handleRestore} disabled={restoring}>
          <Users className="h-3.5 w-3.5 mr-1.5" />
          {restoring ? 'Restoring…' : 'Restore Multi-User Mode'}
        </Button>
      </SettingRow>
    </SectionCard>
  );
}

// ─── Settings Skeleton ────────────────────────────────────────────────────────

function SettingsSkeleton() {
  return (
    <div>
      {/* Page header */}
      <div className="mb-8">
        <h1 className="h-8 w-48 rounded-md bg-muted/50"></h1>
        <p className="h-4 w-64 mt-2 rounded-md bg-muted/50"></p>
      </div>

      {/* Appearance */}
      <div className="table-surface mb-4">
        <div className="px-6 py-4 border-b border-border/50">
          <h2 className="h-3 w-24 rounded bg-muted/50"></h2>
        </div>
        <div className="divide-y divide-border/50">
          <div className="px-6 py-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex-1 min-w-0 sm:mr-8">
              <p className="h-4 w-32 rounded-md bg-muted/50"></p>
              <p className="h-3 w-48 mt-2 rounded-md bg-muted/50"></p>
            </div>
            <div className="shrink-0 flex gap-2">
              <div className="h-12 w-20 rounded-lg bg-muted/50"></div>
              <div className="h-12 w-20 rounded-lg bg-muted/50"></div>
            </div>
          </div>
        </div>
      </div>

      {/* Login mode */}
      <div className="table-surface mb-4">
        <div className="px-6 py-4 border-b border-border/50">
          <h2 className="h-3 w-24 rounded bg-muted/50"></h2>
        </div>
        <div className="divide-y divide-border/50">
          <div className="px-6 py-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex-1 min-w-0 sm:mr-8">
              <p className="h-4 w-48 rounded-md bg-muted/50"></p>
              <p className="h-3 w-64 mt-2 rounded-md bg-muted/50"></p>
            </div>
            <div className="shrink-0 h-9 w-48 rounded-md bg-muted/50"></div>
          </div>
        </div>
      </div>

      {/* General */}
      <div className="table-surface mb-4">
        <div className="px-6 py-4 border-b border-border/50">
          <h2 className="h-3 w-24 rounded bg-muted/50"></h2>
        </div>
        <div className="divide-y divide-border/50">
          <div className="px-6 py-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex-1 min-w-0 sm:mr-8">
              <p className="h-4 w-32 rounded-md bg-muted/50"></p>
              <p className="h-3 w-48 mt-2 rounded-md bg-muted/50"></p>
            </div>
            <div className="shrink-0 h-9 w-32 rounded-md bg-muted/50"></div>
          </div>
          <div className="px-6 py-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex-1 min-w-0 sm:mr-8">
              <p className="h-4 w-32 rounded-md bg-muted/50"></p>
              <p className="h-3 w-48 mt-2 rounded-md bg-muted/50"></p>
            </div>
            <div className="shrink-0 h-9 w-32 rounded-md bg-muted/50"></div>
          </div>
        </div>
      </div>

      {/* Billing */}
      <div className="table-surface mb-4">
        <div className="px-6 py-4 border-b border-border/50">
          <h2 className="h-3 w-24 rounded bg-muted/50"></h2>
        </div>
        <div className="divide-y divide-border/50">
          <div className="px-6 py-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex-1 min-w-0 sm:mr-8">
              <p className="h-4 w-32 rounded-md bg-muted/50"></p>
              <p className="h-3 w-48 mt-2 rounded-md bg-muted/50"></p>
            </div>
            <div className="shrink-0 h-9 w-32 rounded-md bg-muted/50"></div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Link-import preference toggle (localStorage-backed) ─────────────────────

function LinkImportToggle() {
  const [enabled, setEnabled] = useState(getLinkImportPref);

  function toggle(next: boolean) {
    localStorage.setItem(LINK_IMPORT_PREF_KEY, String(next));
    setEnabled(next);
    toast.success(next
      ? 'Past payments will be offered for import when linking a bill.'
      : 'Past payment import prompt is disabled.');
  }

  return (
    <SettingRow
      label="Ask to import past payments when linking"
      description="When you connect a bill to bank transactions (via merchant rule or recommendation), offer to import matching past payments as well."
    >
      <Switch checked={enabled} onCheckedChange={toggle} aria-label="Ask to import past payments when linking" />
    </SettingRow>
  );
}


interface SettingsState {
  currency: string;
  date_format: string;
  week_start: string;
  grace_period_days: number | string;
  drift_threshold_pct: string;
  tracker_show_bank_projection_banner: string;
  tracker_bank_projection_banner_snoozed_until: string;
  tracker_show_search_sort: string;
  tracker_show_summary_cards: string;
  tracker_show_safe_to_spend: string;
  tracker_show_overdue_command_center: string;
  tracker_show_drift_insights: string;
  [key: string]: unknown;
}

// ─── SettingsPage ─────────────────────────────────────────────────────────────

export default function SettingsPage() {
  const DEFAULTS: SettingsState = {
    currency:              'USD',
    date_format:           'MM/DD/YYYY',
    week_start:            '0',
    grace_period_days:     5,
    drift_threshold_pct:   '5',
    tracker_show_bank_projection_banner: 'true',
    tracker_bank_projection_banner_snoozed_until: '',
    tracker_show_search_sort: 'true',
    tracker_show_summary_cards: 'true',
    tracker_show_safe_to_spend: 'true',
    tracker_show_overdue_command_center: 'true',
    tracker_show_drift_insights: 'true',
  };

  const [settings, setSettings] = useState<SettingsState>(DEFAULTS);
  const [loading,   setLoading]   = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);

  const loadSettings = useCallback(() => {
    setLoading(true);
    setLoadError(null);
    api.settings()
      .then((d) => setSettings({ ...DEFAULTS, ...(d as Partial<SettingsState>) }))
      .catch((err) => setLoadError(errMessage(err, 'Failed to load settings')))
      .finally(() => setLoading(false));
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => { loadSettings(); }, [loadSettings]);

  const queryClient = useQueryClient();

  const buildPayload = (s: SettingsState) => ({
    currency: s.currency,
    date_format: s.date_format,
    week_start: s.week_start,
    grace_period_days: s.grace_period_days,
    drift_threshold_pct: s.drift_threshold_pct,
    tracker_show_bank_projection_banner: s.tracker_show_bank_projection_banner,
    tracker_bank_projection_banner_snoozed_until: s.tracker_bank_projection_banner_snoozed_until || '',
    tracker_show_search_sort: s.tracker_show_search_sort,
    tracker_show_summary_cards: s.tracker_show_summary_cards,
    tracker_show_safe_to_spend: s.tracker_show_safe_to_spend,
    tracker_show_overdue_command_center: s.tracker_show_overdue_command_center,
    tracker_show_drift_insights: s.tracker_show_drift_insights,
  });

  // Auto-save: every change persists on its own — no Save button. Toggles and
  // selects feel instant (short debounce); typed inputs get a longer one so we
  // don't save half-typed numbers. After a save, invalidate the ['settings']
  // query so the tracker (which reads its display toggles from that cache) picks
  // up the change instead of showing a stale value for up to its staleTime.
  const { status: saveStatus, schedule } = useAutoSave(
    (payload) => api.saveSettings(payload)
      .then((res) => { queryClient.invalidateQueries({ queryKey: ['settings'] }); return res; })
      .catch((err) => {
        toast.error(errMessage(err, 'Failed to save settings.'));
        throw err;
      }),
  );

  const set = (k: string, v: unknown, delay?: number) => setSettings((p) => {
    const next = { ...p, [k]: v };
    schedule(buildPayload(next), delay);
    return next;
  });
  const setTyped = (k: string, v: unknown) => set(k, v, 900); // for keystroke-driven inputs

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12">
        <SettingsSkeleton />
      </div>
    );
  }

  if (loadError) {
    return (
      <div className="flex flex-col items-center justify-center py-24 text-center rounded-xl border border-destructive/20 bg-destructive/5">
        <AlertCircle className="h-10 w-10 text-destructive mb-3" />
        <p className="text-sm font-medium text-foreground">Failed to load settings</p>
        <p className="mt-1 text-xs text-muted-foreground">{loadError}</p>
        <Button size="sm" variant="outline" onClick={loadSettings}
          className="mt-4 gap-1.5 text-xs border-destructive/30 hover:bg-destructive/10 hover:text-destructive hover:border-destructive/50">
          <RefreshCw className="h-3 w-3" />
          Try again
        </Button>
      </div>
    );
  }

  return (
    <TooltipProvider delayDuration={200}>
    <div>

      {/* Page header — flat on background, live save status on the right */}
      <div className="mb-8 flex items-start justify-between gap-4">
        <div>
          <h1 className="text-2xl font-bold tracking-tight">Settings</h1>
          <p className="text-sm text-muted-foreground mt-0.5">
            Manage your display, billing, and notification preferences · changes save automatically
          </p>
        </div>
        <div className="pt-1.5">
          <SaveStatus status={saveStatus} />
        </div>
      </div>

      {/* Appearance */}
      <AppearanceSection />

      {/* Login mode recovery */}
      <LoginModeRecoverySection />

      {/* General */}
      <SectionCard title="Regional">
        <SettingRow
          label={<span className="inline-flex items-center">Currency<SettingHelp label="Currency" text="Changes how amounts are displayed (symbol and number format). Display only — it doesn't convert values; you still track one currency." /></span>}
          description="How money amounts are shown across the app."
        >
          <Select value={settings.currency} onValueChange={(v) => { setMoneyFormat(v); set('currency', v); }}>
            <SelectTrigger className="w-48">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="USD">USD — US Dollar</SelectItem>
              <SelectItem value="EUR">EUR — Euro</SelectItem>
              <SelectItem value="GBP">GBP — British Pound</SelectItem>
              <SelectItem value="CAD">CAD — Canadian Dollar</SelectItem>
              <SelectItem value="AUD">AUD — Australian Dollar</SelectItem>
              <SelectItem value="CHF">CHF — Swiss Franc</SelectItem>
              <SelectItem value="JPY">JPY — Japanese Yen</SelectItem>
              <SelectItem value="INR">INR — Indian Rupee</SelectItem>
            </SelectContent>
          </Select>
        </SettingRow>

        <SettingRow label="Date format" description="How dates are displayed throughout the app.">
          <Select value={settings.date_format} onValueChange={(v) => { setDateFormat(v); set('date_format', v); }}>
            <SelectTrigger className="w-48">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="MM/DD/YYYY">MM/DD/YYYY</SelectItem>
              <SelectItem value="DD/MM/YYYY">DD/MM/YYYY</SelectItem>
              <SelectItem value="YYYY-MM-DD">YYYY-MM-DD</SelectItem>
            </SelectContent>
          </Select>
        </SettingRow>

        <SettingRow label="First day of week" description="The starting column of the calendar month grid.">
          <Select value={settings.week_start} onValueChange={(v) => set('week_start', v)}>
            <SelectTrigger className="w-48">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="0">Sunday</SelectItem>
              <SelectItem value="1">Monday</SelectItem>
            </SelectContent>
          </Select>
        </SettingRow>
      </SectionCard>

      {/* Tracker Layout */}
      <SectionCard title="Tracker Layout">
        <SettingRow
          label="Bank Projection Banner"
          description="Show the account balance and projected-after-bills banner on the tracker."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_bank_projection_banner)}
            onCheckedChange={(checked) => set('tracker_show_bank_projection_banner', String(checked))}
            aria-label="Show Bank Projection Banner"
          />
        </SettingRow>
        <SettingRow
          label="Search & sort"
          description="Show the tracker search, filters, and sort controls."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_search_sort)}
            onCheckedChange={(checked) => set('tracker_show_search_sort', String(checked))}
            aria-label="Show Search and sort"
          />
        </SettingRow>
        <SettingRow
          label="Summary cards"
          description="Show the bank balance, paid, overdue, previous month, and trend cards."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_summary_cards)}
            onCheckedChange={(checked) => set('tracker_show_summary_cards', String(checked))}
            aria-label="Show Summary cards"
          />
        </SettingRow>
        <SettingRow
          label="Safe to Spend"
          description="Show the safe-to-spend projection card with the payday countdown and upcoming bills."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_safe_to_spend)}
            onCheckedChange={(checked) => set('tracker_show_safe_to_spend', String(checked))}
            aria-label="Show Safe to Spend"
          />
        </SettingRow>
        <SettingRow
          label="Overdue Command Center"
          description="Show the quick-action panel for overdue bills."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_overdue_command_center)}
            onCheckedChange={(checked) => set('tracker_show_overdue_command_center', String(checked))}
            aria-label="Show Overdue Command Center"
          />
        </SettingRow>
        <SettingRow
          label="Drift insights"
          description="Show price-change and bill-drift insights on the tracker."
        >
          <Switch
            checked={settingEnabled(settings.tracker_show_drift_insights)}
            onCheckedChange={(checked) => set('tracker_show_drift_insights', String(checked))}
            aria-label="Show Drift insights"
          />
        </SettingRow>
      </SectionCard>

      {/* Billing Behavior */}
      <SectionCard title="Billing Behavior">
        <LinkImportToggle />
        <SettingRow
          label="Grace period"
          description="Days after the due date before a bill is marked overdue."
        >
          <div className="flex items-center gap-2">
            <Input
              type="number"
              min={0}
              max={30}
              value={settings.grace_period_days}
              onChange={(e) => setTyped('grace_period_days', parseInt(e.target.value, 10) || 0)}
              className="w-20"
            />
            <span className="text-sm text-muted-foreground">days</span>
          </div>
        </SettingRow>
        <SettingRow
          label="Price change sensitivity"
          description="Flag a bill when recent payments differ from the expected amount by at least this percentage."
        >
          <div className="flex items-center gap-2">
            <Input
              type="number"
              min={1}
              max={25}
              step={1}
              value={settings.drift_threshold_pct ?? '5'}
              onChange={(e) => setTyped('drift_threshold_pct', e.target.value)}
              className="w-20 font-mono"
            />
            <span className="text-sm text-muted-foreground">%</span>
          </div>
        </SettingRow>
      </SectionCard>

      {/* Notifications — email + push reminder preferences (auto-save too) */}
      <div id="notifications" className="mt-6 scroll-mt-24">
        <NotificationsSection />
      </div>

      <div id="calendar-feed" className="mt-6 scroll-mt-24">
        <SectionCard title="Calendar Feed">
          <CalendarFeedManager />
        </SectionCard>
      </div>

    </div>
    </TooltipProvider>
  );
}
