'use client';

/**
 * Self-service security center. Renders three independent cards:
 *
 * 1. **Change password** — current + new with strength rule (≥8 chars, mixed
 *    case + digit). Backend revokes all other sessions on success.
 * 2. **Two-factor authentication (TOTP)** — enable by scanning a QR or
 *    typing the secret into an authenticator app, confirm with a 6-digit
 *    code. Disable requires current password.
 * 3. **Active sessions** — list of every signed-in device with last-active
 *    time + "this device" marker. Revoke any to sign out elsewhere.
 *
 * Component is portal-agnostic — same file is shipped to patient, admin,
 * and doctor portals.
 */

import { useCallback, useEffect, useState } from 'react';
import {
  AlertCircle,
  CheckCircle2,
  KeyRound,
  Loader2,
  Monitor,
  RefreshCw,
  ShieldCheck,
  ShieldOff,
  Smartphone,
  Trash2,
} from 'lucide-react';
import { Button, GlassCard, Input } from '@sehat/ui';

interface SessionRow {
  id: string;
  deviceName: string | null;
  userAgent: string | null;
  ipAddress: string | null;
  createdAt: string;
  lastUsedAt: string | null;
  expiresAt: string;
  isCurrent: boolean;
}

export interface SecurityPanelProps {
  /** Current MFA state from the session — used to pick the initial card mode. */
  mfaEnabled: boolean;
  /** Called after a successful change so the host can refresh the user state. */
  onChanged?: () => void;
}

export function SecurityPanel({ mfaEnabled: initialMfaEnabled, onChanged }: SecurityPanelProps) {
  const [mfaEnabled, setMfaEnabled] = useState(initialMfaEnabled);
  // Sync if parent refreshes user
  useEffect(() => setMfaEnabled(initialMfaEnabled), [initialMfaEnabled]);

  return (
    <div className="space-y-6">
      <ChangePasswordCard onChanged={onChanged} />
      <MfaCard
        enabled={mfaEnabled}
        onChange={(next) => {
          setMfaEnabled(next);
          onChanged?.();
        }}
      />
      <SessionsCard />
    </div>
  );
}

// ===== Change password =====

function ChangePasswordCard({ onChanged }: { onChanged?: () => void }) {
  const [current, setCurrent] = useState('');
  const [next, setNext] = useState('');
  const [confirm, setConfirm] = useState('');
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState(false);

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    setSuccess(false);
    if (next.length < 8) {
      setError('New password must be at least 8 characters.');
      return;
    }
    if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(next)) {
      setError('New password must include lowercase, uppercase, and a digit.');
      return;
    }
    if (next !== confirm) {
      setError('Confirmation does not match.');
      return;
    }
    setSaving(true);
    try {
      const r = await fetch('/api/auth/change-password', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ currentPassword: current, newPassword: next }),
      });
      if (!r.ok) {
        const body = await r.json().catch(() => ({}));
        throw new Error(body.message ?? 'Failed to change password');
      }
      setCurrent('');
      setNext('');
      setConfirm('');
      setSuccess(true);
      onChanged?.();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setSaving(false);
    }
  }

  return (
    <GlassCard tone="light" padding="lg">
      <h2 className="mb-2 flex items-center gap-2 text-sm font-semibold text-ink-2">
        <KeyRound className="h-4 w-4" /> Change password
      </h2>
      <p className="mb-4 text-xs text-ink-3">
        After a successful change, every <em>other</em> device is signed out automatically.
      </p>
      <form onSubmit={submit} className="space-y-3">
        <Input
          label="Current password"
          type="password"
          value={current}
          onChange={(e) => setCurrent(e.target.value)}
          required
          autoComplete="current-password"
        />
        <Input
          label="New password"
          type="password"
          value={next}
          onChange={(e) => setNext(e.target.value)}
          required
          autoComplete="new-password"
          hint="≥ 8 chars, must include lowercase + uppercase + a digit"
        />
        <Input
          label="Confirm new password"
          type="password"
          value={confirm}
          onChange={(e) => setConfirm(e.target.value)}
          required
          autoComplete="new-password"
        />
        {error ? <FormAlert kind="error" text={error} /> : null}
        {success ? <FormAlert kind="success" text="Password updated. Other devices have been signed out." /> : null}
        <Button type="submit" variant="primary" size="md" loading={saving}>
          Update password
        </Button>
      </form>
    </GlassCard>
  );
}

// ===== MFA =====

function MfaCard({ enabled, onChange }: { enabled: boolean; onChange: (next: boolean) => void }) {
  const [phase, setPhase] = useState<'idle' | 'setup' | 'verify' | 'disable'>('idle');
  const [secret, setSecret] = useState('');
  const [otpauthUrl, setOtpauthUrl] = useState('');
  const [code, setCode] = useState('');
  const [password, setPassword] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState<string | null>(null);

  async function startSetup() {
    setBusy(true);
    setError(null);
    try {
      const r = await fetch('/api/auth/mfa/setup', { method: 'POST' });
      if (!r.ok) {
        const body = await r.json().catch(() => ({}));
        throw new Error(body.message ?? 'Could not start MFA setup');
      }
      const data = (await r.json()) as { secret: string; otpauthUrl: string };
      setSecret(data.secret);
      setOtpauthUrl(data.otpauthUrl);
      setPhase('verify');
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  async function confirmSetup(e: React.FormEvent) {
    e.preventDefault();
    setBusy(true);
    setError(null);
    try {
      const r = await fetch('/api/auth/mfa/verify', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ code }),
      });
      if (!r.ok) {
        const body = await r.json().catch(() => ({}));
        throw new Error(body.message ?? 'Invalid code');
      }
      setPhase('idle');
      setCode('');
      setSecret('');
      setOtpauthUrl('');
      setSuccess('Two-factor authentication is now on.');
      onChange(true);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  async function disable(e: React.FormEvent) {
    e.preventDefault();
    setBusy(true);
    setError(null);
    try {
      const r = await fetch('/api/auth/mfa/disable', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password }),
      });
      if (!r.ok) {
        const body = await r.json().catch(() => ({}));
        throw new Error(body.message ?? 'Could not disable MFA');
      }
      setPassword('');
      setPhase('idle');
      setSuccess('Two-factor authentication is now off.');
      onChange(false);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  // Google chart QR — simplest dependency-free QR for an otpauth:// URL.
  const qrUrl = otpauthUrl
    ? `https://api.qrserver.com/v1/create-qr-code/?size=192x192&data=${encodeURIComponent(otpauthUrl)}`
    : '';

  return (
    <GlassCard tone="light" padding="lg">
      <h2 className="mb-2 flex items-center gap-2 text-sm font-semibold text-ink-2">
        <ShieldCheck className="h-4 w-4" />
        Two-factor authentication (TOTP)
      </h2>
      <p className="mb-4 text-xs text-ink-3">
        Use Google Authenticator, 1Password, Authy, or any TOTP-compatible app. Once enabled, every
        sign-in will require a 6-digit code.
      </p>

      {enabled && phase === 'idle' ? (
        <div className="space-y-3">
          <FormAlert kind="success" text="Two-factor authentication is on for your account." />
          <Button
            type="button"
            variant="secondary"
            size="md"
            onClick={() => {
              setPhase('disable');
              setSuccess(null);
            }}
          >
            <ShieldOff className="mr-1 inline h-4 w-4" /> Turn off MFA
          </Button>
        </div>
      ) : null}

      {!enabled && phase === 'idle' ? (
        <div className="space-y-3">
          {success ? <FormAlert kind="success" text={success} /> : null}
          {error ? <FormAlert kind="error" text={error} /> : null}
          <Button type="button" variant="primary" size="md" onClick={() => void startSetup()} loading={busy}>
            <Smartphone className="mr-1 inline h-4 w-4" /> Enable MFA
          </Button>
        </div>
      ) : null}

      {phase === 'verify' ? (
        <form onSubmit={confirmSetup} className="space-y-3">
          <div className="rounded-lg border border-surface-border bg-surface-alt/40 p-4">
            <p className="mb-3 text-xs font-semibold text-ink-2">
              1. Scan this QR with your authenticator app
            </p>
            {qrUrl ? (
              <img
                src={qrUrl}
                alt="MFA QR code"
                className="mx-auto h-48 w-48 rounded-lg border border-surface-border bg-white"
              />
            ) : null}
            <p className="mt-3 text-xs text-ink-3">
              Can&apos;t scan? Type this secret manually:
            </p>
            <code className="mt-1 block break-all rounded bg-white px-2 py-1 font-mono text-xs">
              {secret}
            </code>
          </div>
          <Input
            label="2. Enter the 6-digit code from the app"
            value={code}
            onChange={(e) => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
            placeholder="123456"
            required
            inputMode="numeric"
            autoComplete="one-time-code"
          />
          {error ? <FormAlert kind="error" text={error} /> : null}
          <div className="flex gap-2">
            <Button type="submit" variant="primary" size="md" loading={busy} disabled={code.length !== 6}>
              Confirm &amp; enable
            </Button>
            <button
              type="button"
              onClick={() => {
                setPhase('idle');
                setCode('');
                setSecret('');
                setOtpauthUrl('');
                setError(null);
              }}
              className="rounded-lg border border-surface-border bg-white px-4 py-2 text-sm font-semibold text-ink-muted"
            >
              Cancel
            </button>
          </div>
        </form>
      ) : null}

      {phase === 'disable' ? (
        <form onSubmit={disable} className="space-y-3">
          <p className="text-xs text-ink-3">Confirm your password to disable MFA.</p>
          <Input
            label="Current password"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
            autoComplete="current-password"
          />
          {error ? <FormAlert kind="error" text={error} /> : null}
          <div className="flex gap-2">
            <Button type="submit" variant="primary" size="md" loading={busy}>
              Disable MFA
            </Button>
            <button
              type="button"
              onClick={() => {
                setPhase('idle');
                setPassword('');
                setError(null);
              }}
              className="rounded-lg border border-surface-border bg-white px-4 py-2 text-sm font-semibold text-ink-muted"
            >
              Cancel
            </button>
          </div>
        </form>
      ) : null}
    </GlassCard>
  );
}

// ===== Sessions =====

function SessionsCard() {
  const [sessions, setSessions] = useState<SessionRow[] | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [revoking, setRevoking] = useState<string | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const r = await fetch('/api/me/sessions');
      if (!r.ok) throw new Error('Could not load sessions');
      setSessions(((await r.json()) as SessionRow[]) ?? []);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, []);

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

  async function revoke(id: string) {
    setRevoking(id);
    try {
      const r = await fetch(`/api/me/sessions/${id}`, { method: 'DELETE' });
      if (!r.ok && r.status !== 204) throw new Error('Could not sign out that device');
      await load();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setRevoking(null);
    }
  }

  return (
    <GlassCard tone="light" padding="lg">
      <div className="mb-4 flex items-center justify-between">
        <h2 className="flex items-center gap-2 text-sm font-semibold text-ink-2">
          <Monitor className="h-4 w-4" /> Active devices
        </h2>
        <button
          type="button"
          onClick={() => void load()}
          className="inline-flex items-center gap-1 rounded-md border border-surface-border bg-white px-2 py-1 text-xs font-semibold text-ink-muted hover:border-brand-300"
        >
          <RefreshCw className={`h-3 w-3 ${loading ? 'animate-spin' : ''}`} /> Refresh
        </button>
      </div>
      <p className="mb-3 text-xs text-ink-3">
        These devices are signed in to your account. Revoke any you don&apos;t recognise.
      </p>

      {error ? <FormAlert kind="error" text={error} /> : null}

      {loading && !sessions ? (
        <p className="text-sm text-ink-3">Loading…</p>
      ) : !sessions || sessions.length === 0 ? (
        <p className="text-sm text-ink-3">No active sessions found.</p>
      ) : (
        <ul className="space-y-2">
          {sessions.map((s) => (
            <li
              key={s.id}
              className={`flex items-start justify-between gap-3 rounded-lg border px-3 py-2 ${
                s.isCurrent ? 'border-brand-300 bg-brand-50/40' : 'border-surface-border bg-white'
              }`}
            >
              <div className="min-w-0">
                <p className="flex items-center gap-2 text-sm font-semibold text-ink">
                  {s.deviceName ?? 'Unknown device'}
                  {s.isCurrent ? (
                    <span className="rounded-full bg-brand px-2 py-0.5 text-[10px] font-bold uppercase text-white">
                      This device
                    </span>
                  ) : null}
                </p>
                <p className="mt-0.5 text-xs text-ink-muted">
                  {s.ipAddress ?? 'IP unknown'}
                  {' · '}
                  Last active {fmtRelative(s.lastUsedAt ?? s.createdAt)}
                </p>
                {s.userAgent ? (
                  <p className="mt-0.5 truncate text-[11px] text-ink-subtle" title={s.userAgent}>
                    {s.userAgent}
                  </p>
                ) : null}
              </div>
              <button
                type="button"
                onClick={() => void revoke(s.id)}
                disabled={revoking === s.id}
                className="flex-shrink-0 rounded-md border border-surface-border bg-white p-1.5 text-ink-muted hover:border-error/40 hover:text-error disabled:opacity-50"
                title={s.isCurrent ? 'Sign out (will end this session)' : 'Sign out this device'}
                aria-label="Sign out this device"
              >
                {revoking === s.id ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
              </button>
            </li>
          ))}
        </ul>
      )}
    </GlassCard>
  );
}

// ===== Helpers =====

function FormAlert({ kind, text }: { kind: 'error' | 'success'; text: string }) {
  const Icon = kind === 'error' ? AlertCircle : CheckCircle2;
  const cls =
    kind === 'error'
      ? 'border-error/30 bg-error/10 text-error'
      : 'border-success/30 bg-success/10 text-success';
  return (
    <div className={`flex items-start gap-2 rounded-md border p-2.5 text-xs ${cls}`}>
      <Icon className="mt-0.5 h-3.5 w-3.5 flex-shrink-0" />
      <span>{text}</span>
    </div>
  );
}

function fmtRelative(iso: string): string {
  const t = new Date(iso).getTime();
  if (!Number.isFinite(t)) return iso;
  const diffMs = Date.now() - t;
  const min = Math.round(diffMs / 60_000);
  if (min < 1) return 'just now';
  if (min < 60) return `${min} min ago`;
  const hr = Math.round(min / 60);
  if (hr < 24) return `${hr} hr ago`;
  const d = Math.round(hr / 24);
  if (d < 30) return `${d} day${d === 1 ? '' : 's'} ago`;
  return new Date(iso).toLocaleDateString();
}
