import { useEffect, useState } from 'react';
import { Lock, Bell, Cpu, FolderMinus, Save, ArrowUpRight } from 'lucide-react';
import { Card, CardBody, CardHeader, CardTitle, CardDescription, CardFooter } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Field, Input, Select, Switch } from '@/components/ui/Input';
import { Loading, ErrorState, Toast } from '@/components/ui/States';
import { api } from '@/lib/api';
import { useQuery, useMutation } from '@/hooks/useQuery';
import { useApp } from '@/App';
import { MaintenanceCard } from '@/components/MaintenanceCard';
import { cn } from '@/lib/cn';

/**
 * Settings state mirrors the server's allowlist in
 * `includes/api/class-settings-controller.php::update()`. Dropped keys:
 *   - notify_email / notify_on_failure / notify_on_success — moved to the
 *     Notifications sidebar page (multi-channel). A legacy `notify_email`
 *     in wp_options is auto-migrated into an email notifier on plugin
 *     upgrade by Installer::migrate_legacy_email_notifier().
 *   - chunk_size_mb — auto-tuned from PHP's memory_limit by
 *     ArchiveWriter::recommended_chunk_mb(). The dropdown was never read.
 */
interface SettingsState {
  encryption: boolean;
  encryption_passphrase: string;
  compression_level: number;
  maintenance_on_restore: boolean;
  exclusions: string[];
}

const defaults: SettingsState = {
  encryption: false,
  encryption_passphrase: '',
  compression_level: 6,
  maintenance_on_restore: true,
  exclusions: [],
};

export function Settings() {
  const { data, isLoading, error, refetch } = useQuery(() => api.settings.get(), []);
  const [form, setForm] = useState<SettingsState>(defaults);
  // Confirm-passphrase is UI-only state — it never goes to the server. The
  // server stores only the real passphrase. The confirm field's job is to
  // catch typos before save: if encryption is enabled and the two fields
  // disagree, we block save and surface the mismatch with a red ring.
  const [confirmPass, setConfirmPass] = useState('');
  const [confirmError, setConfirmError] = useState(false);
  const [toast, setToast] = useState<{ msg: string; tone: 'success' | 'danger' } | null>(null);
  const { navigate } = useApp();

  useEffect(() => {
    if (data) {
      setForm({
        ...defaults,
        ...(data as any),
        exclusions: ((data as any).exclusions ?? []) as string[],
      });
    }
  }, [data]);

  const save = useMutation(
    (s: SettingsState) => api.settings.update(s as unknown as Record<string, unknown>),
    { onSuccess: () => {
        setToast({ msg: 'Settings saved', tone: 'success' });
        // Clear the confirm field after a successful save so the user
        // doesn't see a stale clear-text passphrase sitting there.
        setConfirmPass('');
        setConfirmError(false);
        refetch();
      },
      onError:   (e) => setToast({ msg: e.message, tone: 'danger' }) },
  );

  if (isLoading) return <Loading label="Loading settings…" />;
  if (error)     return <ErrorState error={error} onRetry={refetch} />;

  const update = <K extends keyof SettingsState>(k: K, v: SettingsState[K]) => setForm({ ...form, [k]: v });

  /**
   * Validate then save. Mismatched passphrases block save with a red ring on
   * the confirm field. The check only runs when encryption is enabled AND
   * the user actually entered a new passphrase (the server returns the
   * existing one as `***`, so an unchanged form has `encryption_passphrase`
   * === '***' and we shouldn't ask them to re-confirm what they didn't type).
   */
  const handleSave = () => {
    if (form.encryption && form.encryption_passphrase && form.encryption_passphrase !== '***') {
      if (form.encryption_passphrase !== confirmPass) {
        setConfirmError(true);
        setToast({ msg: "Passphrases don't match. Please re-type the confirm field.", tone: 'danger' });
        return;
      }
    }
    setConfirmError(false);
    save.mutate(form);
  };

  return (
    <div className="space-y-4 max-w-[1400px]">
      <MaintenanceCard
        autoDuringRestore={form.maintenance_on_restore}
        onAutoDuringRestoreChange={(v) => update('maintenance_on_restore', v)}
      />

      <SettingsCard icon={<Lock className="h-4 w-4" />} title="Encryption" desc="Encrypt archives at rest with AES-256-GCM">
        <div className="flex items-center justify-between">
          <span className="text-sm text-ink-800">Enable archive encryption</span>
          <Switch checked={form.encryption} onChange={(v) => update('encryption', v)} />
        </div>
        {form.encryption && (
          <div className="grid grid-cols-2 gap-3 mt-3">
            <Field label="Passphrase" hint="Required to restore. Store it safely.">
              <Input
                type="password"
                placeholder="•••••••••••••"
                value={form.encryption_passphrase}
                onChange={(e) => {
                  update('encryption_passphrase', e.target.value);
                  // Typing in the primary field clears any stale mismatch
                  // warning. The actual check still runs at save time.
                  if (confirmError) setConfirmError(false);
                }}
              />
            </Field>
            <Field
              label="Confirm passphrase"
              hint={confirmError ? "Doesn't match the passphrase above." : undefined}
            >
              <Input
                type="password"
                placeholder="•••••••••••••"
                value={confirmPass}
                onChange={(e) => {
                  setConfirmPass(e.target.value);
                  if (confirmError) setConfirmError(false);
                }}
                className={cn(confirmError && 'border-red-500 ring-2 ring-red-100 focus:border-red-500 focus:ring-red-200')}
              />
            </Field>
          </div>
        )}
      </SettingsCard>

      {/* Notifications were moved to their own sidebar page (multi-channel:
          email, Slack, Discord, Telegram, etc.). This in-page card replaces
          the old, dead "email-only" controls so a user looking for them
          here gets a one-click jump to the real surface. */}
      <Card>
        <CardBody className="flex items-center gap-3">
          <span className="h-8 w-8 grid place-items-center rounded-lg bg-ink-100 text-ink-700 shrink-0">
            <Bell className="h-4 w-4" />
          </span>
          <div className="flex-1 min-w-0">
            <p className="text-sm font-medium text-ink-900">Notifications</p>
            <p className="text-xs text-ink-500 mt-0.5">
              Email, Slack, Discord, Telegram, and other channels are configured on the Notifications page.
            </p>
          </div>
          <Button
            variant="secondary"
            size="sm"
            rightIcon={<ArrowUpRight className="h-3.5 w-3.5" />}
            onClick={() => navigate('notifications')}
          >
            Open Notifications
          </Button>
        </CardBody>
      </Card>

      <SettingsCard icon={<Cpu className="h-4 w-4" />} title="Performance" desc="Tune for your server's resources">
        <Field label="Compression"
          hint="zip deflate level. Higher = smaller archive but more CPU. Media files (images, video) are always stored uncompressed regardless.">
          <Select value={String(form.compression_level)} onChange={(e) => update('compression_level', parseInt(e.target.value))}>
            <option value="0">Store (no compression, fastest)</option>
            <option value="3">Fast (small savings, low CPU)</option>
            <option value="6">Default (recommended balance)</option>
            <option value="9">Best (slowest, smallest archive)</option>
          </Select>
        </Field>
      </SettingsCard>

      <SettingsCard icon={<FolderMinus className="h-4 w-4" />} title="Exclusions" desc="Files and folders to skip">
        <Field label="Path patterns" hint="One per line. Supports * wildcards.">
          <textarea
            value={form.exclusions.join('\n')}
            onChange={(e) => update('exclusions', e.target.value.split('\n').map((s) => s.trim()).filter(Boolean))}
            className="w-full min-h-[120px] rounded-lg border border-ink-200 bg-white px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-brand-400 focus:border-brand-500"
          />
        </Field>
      </SettingsCard>

      <Card>
        <CardFooter className="justify-end gap-2">
          <Button variant="ghost" onClick={() => refetch()}>Reset</Button>
          <Button variant="primary" leftIcon={<Save className="h-4 w-4" />} disabled={save.isLoading}
            onClick={handleSave}>
            {save.isLoading ? 'Saving…' : 'Save settings'}
          </Button>
        </CardFooter>
      </Card>

      {toast && <Toast message={toast.msg} tone={toast.tone} onClose={() => setToast(null)} />}
    </div>
  );
}

function SettingsCard({ icon, title, desc, children }: { icon: React.ReactNode; title: string; desc: string; children: React.ReactNode }) {
  return (
    <Card>
      <CardHeader>
        <div className="flex items-center gap-3">
          <span className="h-8 w-8 grid place-items-center rounded-lg bg-ink-100 text-ink-700">{icon}</span>
          <div>
            <CardTitle>{title}</CardTitle>
            <CardDescription>{desc}</CardDescription>
          </div>
        </div>
      </CardHeader>
      <CardBody>{children}</CardBody>
    </Card>
  );
}
