'use client';

import { useEffect, useState } from 'react';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import { Check, Circle, Loader2, ExternalLink } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { apiFetch } from '@/lib/api/client';

interface OnboardingStep {
  id: string;
  href: string;
  label: string;
  description: string;
  /** Setting key whose presence proves the step is done. When set, the
   *  checkmark auto-fills from the settings list. When undefined, the
   *  step relies on the manual checkbox in `onboarding_status`. */
  autoCheckSettingKey?: string;
  /** Multi-key gate: all listed setting keys must be present (non-empty)
   *  for the step to auto-complete. Useful for compound checks where a
   *  single key would falsely mark "done" — e.g. Documenso needs a URL
   *  plus signer identity plus a template id, not just the URL. */
  autoCheckSettingKeysAll?: readonly string[];
  /** Override: read this many users / tags / roles from a list endpoint
   *  and consider the step done when count > 0. */
  autoCheckListEndpoint?: string;
}

const STEPS: OnboardingStep[] = [
  {
    id: 'branding',
    href: 'branding',
    label: 'Set port name, logo, primary colour',
    description: 'Branding flows into the navbar, emails, EOI PDFs, and the public auth shell.',
    autoCheckSettingKey: 'branding_logo_url',
  },
  {
    id: 'email',
    href: 'email',
    label: 'Configure outgoing email',
    description:
      'From-address, signature, footer, plus per-port SMTP overrides if you don’t use the global account.',
    autoCheckSettingKey: 'smtp_host_override',
  },
  {
    id: 'documenso',
    href: 'documenso',
    label: 'Connect Documenso for EOIs',
    description:
      'API credentials, the EOI template id, plus the developer + approver identity that signs every EOI.',
    // Compound gate: an EOI cannot be sent without ALL of these. A
    // port-admin who saves only the URL would otherwise see the step go
    // green and discover the gap on first EOI attempt (Documenso 404s
    // on a missing template, or sends recipients with empty names).
    autoCheckSettingKeysAll: [
      'documenso_api_url_override',
      'documenso_developer_email',
      'documenso_approver_email',
      'documenso_eoi_template_id',
    ],
  },
  {
    id: 'settings',
    href: 'settings',
    label: 'Tune business rules + recommender weights',
    description:
      'Pipeline weights, net-10 discount, berth recommender knobs (heat weights, fall-through policy).',
    // Recommender defaults are layered (port > global > built-in), so a
    // port that uses the built-ins never writes a row. Use a tuned
    // heat-weight as the "admin actually saw + chose" sentinel instead.
    autoCheckSettingKey: 'heat_weight_recency',
  },
  {
    id: 'roles',
    href: 'roles',
    label: 'Create roles & assign users',
    description: 'Per-port roles inherit from system roles; override permissions here.',
    autoCheckListEndpoint: '/api/v1/admin/roles',
  },
  {
    id: 'users',
    href: 'users',
    label: 'Invite the rest of the team',
    description:
      'Invite users, assign roles, optionally grant residential access. Track pending vs accepted.',
    autoCheckListEndpoint: '/api/v1/admin/users',
  },
  {
    id: 'tags',
    href: 'tags',
    label: 'Define starter tags',
    description: 'Color-coded labels used across clients, yachts, companies, and interests.',
    autoCheckListEndpoint: '/api/v1/tags/options',
  },
  {
    id: 'storage',
    href: 'storage',
    label: 'Configure storage backend',
    description:
      'Verify S3/filesystem and run a test connection before going live so PDFs and avatars persist correctly.',
    autoCheckSettingKey: 'storage_backend',
  },
  {
    id: 'forms',
    href: 'forms',
    label: 'Wire the website intake forms',
    description:
      'Inquiry forms on the marketing site dual-write into the CRM via /api/public/website-inquiries. Manually mark complete when verified.',
  },
];

interface SettingRow {
  key: string;
  value: unknown;
  portId: string | null;
}
interface SettingsResp {
  data: { portSettings: SettingRow[]; globalSettings: SettingRow[] };
}

export function OnboardingChecklist() {
  const params = useParams<{ portSlug: string }>();
  const portSlug = params?.portSlug ?? '';
  const [autoChecks, setAutoChecks] = useState<Record<string, boolean>>({});
  const [manualChecks, setManualChecks] = useState<Record<string, boolean>>({});
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState<string | null>(null);

  useEffect(() => {
    async function load() {
      setLoading(true);
      try {
        const settings = await apiFetch<SettingsResp>('/api/v1/admin/settings');
        const all = [...settings.data.portSettings, ...settings.data.globalSettings];
        const byKey = new Map(all.map((r) => [r.key, r.value]));

        const isPresent = (v: unknown) => v !== undefined && v !== null && v !== '' && v !== false;

        const checks: Record<string, boolean> = {};
        const listChecks = await Promise.all(
          STEPS.map(async (s) => {
            if (s.autoCheckSettingKey) {
              return [s.id, isPresent(byKey.get(s.autoCheckSettingKey))] as const;
            }
            if (s.autoCheckSettingKeysAll) {
              return [
                s.id,
                s.autoCheckSettingKeysAll.every((k) => isPresent(byKey.get(k))),
              ] as const;
            }
            if (s.autoCheckListEndpoint) {
              try {
                const res = await apiFetch<{ data: unknown[] }>(s.autoCheckListEndpoint);
                return [s.id, Array.isArray(res.data) && res.data.length > 0] as const;
              } catch {
                return [s.id, false] as const;
              }
            }
            return [s.id, false] as const;
          }),
        );
        for (const [id, done] of listChecks) checks[id] = done;
        setAutoChecks(checks);

        // Pull the manual-checkbox state from system_settings.
        const manual = (byKey.get('onboarding_manual_status') ?? {}) as Record<string, boolean>;
        setManualChecks(manual);
      } finally {
        setLoading(false);
      }
    }
    void load();
  }, []);

  async function toggleManual(id: string) {
    const next = { ...manualChecks, [id]: !manualChecks[id] };
    setManualChecks(next);
    setSaving(id);
    try {
      await apiFetch('/api/v1/admin/settings', {
        method: 'PUT',
        body: { key: 'onboarding_manual_status', value: next },
      });
    } finally {
      setSaving(null);
    }
  }

  const stepDone = (id: string) => Boolean(autoChecks[id]) || Boolean(manualChecks[id]);
  const completed = STEPS.filter((s) => stepDone(s.id)).length;
  const percent = Math.round((completed / STEPS.length) * 100);

  return (
    <div className="mt-6 space-y-6">
      <Card>
        <CardHeader>
          <CardTitle>Setup checklist</CardTitle>
          <CardDescription>
            {completed} of {STEPS.length} complete. Auto-checked steps update when you save the
            underlying setting; manual ones (like website-form integration) need the checkbox.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-5">
          <Progress value={percent} className="h-2" />

          <ol className="space-y-3">
            {STEPS.map((step, idx) => {
              const auto = Boolean(autoChecks[step.id]);
              const manual = Boolean(manualChecks[step.id]);
              const done = auto || manual;
              return (
                <li
                  key={step.id}
                  className={
                    done
                      ? 'flex items-start gap-3 rounded-md border border-emerald-200 bg-emerald-50/50 p-3'
                      : 'flex items-start gap-3 rounded-md border p-3'
                  }
                >
                  <span
                    className={
                      done
                        ? 'mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-emerald-500 text-white'
                        : 'mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground'
                    }
                  >
                    {done ? (
                      <Check className="h-4 w-4" aria-hidden />
                    ) : loading ? (
                      <Loader2 className="h-4 w-4 animate-spin" aria-hidden />
                    ) : (
                      <Circle className="h-4 w-4" aria-hidden />
                    )}
                  </span>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-start justify-between gap-2">
                      <div>
                        <Link
                          href={`/${portSlug}/admin/${step.href}` as never}
                          className="text-sm font-medium hover:underline inline-flex items-center gap-1"
                        >
                          {idx + 1}. {step.label}
                          <ExternalLink className="h-3 w-3 opacity-50" aria-hidden />
                        </Link>
                        <p className="mt-0.5 text-xs text-muted-foreground">{step.description}</p>
                        {auto && (
                          <p className="mt-1 text-[11px] text-emerald-700">
                            Auto-detected complete via{' '}
                            <code className="text-[10px]">
                              {step.autoCheckSettingKey ??
                                step.autoCheckSettingKeysAll?.join(' + ') ??
                                step.autoCheckListEndpoint}
                            </code>
                          </p>
                        )}
                      </div>
                      {!auto && (
                        <Button
                          size="sm"
                          variant={manual ? 'secondary' : 'outline'}
                          disabled={saving === step.id}
                          onClick={() => toggleManual(step.id)}
                        >
                          {saving === step.id ? (
                            <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden />
                          ) : manual ? (
                            'Mark incomplete'
                          ) : (
                            'Mark done'
                          )}
                        </Button>
                      )}
                    </div>
                  </div>
                </li>
              );
            })}
          </ol>
        </CardContent>
      </Card>
    </div>
  );
}
