'use client';

import { useEffect, useState } from 'react';
import { GripVertical, Plus, Trash2, Loader2, Save } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { WarningCallout } from '@/components/ui/warning-callout';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import { toast } from 'sonner';

interface Stage {
  id: string;
  label: string;
  terminal: 'won' | 'lost' | null;
}

interface Orphan {
  id: string;
  pipelineStage: string;
}

interface Resp {
  data: { stages: Stage[]; orphans: Orphan[] };
}

export function ResidentialStagesAdmin() {
  const [stages, setStages] = useState<Stage[]>([]);
  const [originalIds, setOriginalIds] = useState<Set<string>>(new Set());
  const [orphans, setOrphans] = useState<Orphan[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [reassignDialog, setReassignDialog] = useState<{
    affected: Orphan[];
    reassignments: Record<string, string>;
  } | null>(null);

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

  async function load() {
    setLoading(true);
    try {
      const res = await apiFetch<Resp>('/api/v1/residential/stages');
      setStages(res.data.stages);
      setOriginalIds(new Set(res.data.stages.map((s) => s.id)));
      setOrphans(res.data.orphans);
    } finally {
      setLoading(false);
    }
  }

  function move(idx: number, dir: -1 | 1) {
    const next = [...stages];
    const swap = idx + dir;
    if (swap < 0 || swap >= next.length) return;
    [next[idx], next[swap]] = [next[swap]!, next[idx]!];
    setStages(next);
  }

  function update(idx: number, patch: Partial<Stage>) {
    setStages((prev) => prev.map((s, i) => (i === idx ? { ...s, ...patch } : s)));
  }

  function add() {
    setStages((prev) => [
      ...prev,
      { id: `stage_${prev.length + 1}`, label: 'New stage', terminal: null },
    ]);
  }

  function remove(idx: number) {
    setStages((prev) => prev.filter((_, i) => i !== idx));
  }

  async function attemptSave(force: boolean, reassignments?: Record<string, string>) {
    setSaving(true);
    try {
      await apiFetch('/api/v1/residential/stages', {
        method: 'PUT',
        body: { stages, reassignments, force },
      });
      toast.success('Stages saved');
      setReassignDialog(null);
      await load();
    } catch (err: unknown) {
      // The service throws ConflictError when interests sit on a removed
      // stage. Open the reassignment dialog so the admin can fix it
      // before retrying.
      const msg = err instanceof Error ? err.message : '';
      if (/sit on a stage/.test(msg)) {
        // Build the affected list from the current orphan-snapshot
        // filtered to stages NOT in the new list.
        const newIds = new Set(stages.map((s) => s.id));
        const affected = orphans.filter((o) => !newIds.has(o.pipelineStage));
        setReassignDialog({ affected, reassignments: {} });
      } else {
        toastError(err);
      }
    } finally {
      setSaving(false);
    }
  }

  const stageIds = stages.map((s) => s.id);

  const removedStageIds = Array.from(originalIds).filter((id) => !stageIds.includes(id));

  if (loading) {
    return (
      <div className="flex items-center gap-2 text-sm text-muted-foreground">
        <Loader2 className="h-4 w-4 animate-spin" aria-hidden /> Loading stages…
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <Card>
        <CardHeader>
          <CardTitle>Stages</CardTitle>
          <CardDescription>
            Drag-style ordering via the up/down handles on the right. Stages with terminal
            &ldquo;won&rdquo; or &ldquo;lost&rdquo; mark the funnel ends and feed reports.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-3">
          {stages.map((stage, idx) => (
            <div
              key={`${stage.id}-${idx}`}
              className="flex items-center gap-3 rounded-md border p-3"
            >
              <GripVertical className="h-4 w-4 text-muted-foreground" aria-hidden />
              <div className="flex-1 grid grid-cols-1 sm:grid-cols-3 gap-2">
                <div className="space-y-1">
                  <Label className="text-xs uppercase tracking-wide text-muted-foreground">
                    Id
                  </Label>
                  <Input
                    value={stage.id}
                    onChange={(e) => update(idx, { id: e.target.value })}
                    className="font-mono text-xs h-8"
                  />
                </div>
                <div className="space-y-1">
                  <Label className="text-xs uppercase tracking-wide text-muted-foreground">
                    Label
                  </Label>
                  <Input
                    value={stage.label}
                    onChange={(e) => update(idx, { label: e.target.value })}
                    className="h-8"
                  />
                </div>
                <div className="space-y-1">
                  <Label className="text-xs uppercase tracking-wide text-muted-foreground">
                    Terminal
                  </Label>
                  <Select
                    value={stage.terminal ?? 'none'}
                    onValueChange={(v) =>
                      update(idx, {
                        terminal: v === 'none' ? null : (v as 'won' | 'lost'),
                      })
                    }
                  >
                    <SelectTrigger className="h-8">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="none">In-progress</SelectItem>
                      <SelectItem value="won">Closed - won</SelectItem>
                      <SelectItem value="lost">Closed - lost</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
              </div>
              <div className="flex flex-col gap-1">
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="h-7 px-2"
                  onClick={() => move(idx, -1)}
                  disabled={idx === 0}
                >
                  ↑
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="h-7 px-2"
                  onClick={() => move(idx, 1)}
                  disabled={idx === stages.length - 1}
                >
                  ↓
                </Button>
              </div>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={() => remove(idx)}
                className="text-destructive"
              >
                <Trash2 className="h-3.5 w-3.5" aria-hidden />
              </Button>
            </div>
          ))}

          <Button type="button" variant="outline" size="sm" onClick={add}>
            <Plus className="mr-1.5 h-3.5 w-3.5" aria-hidden />
            Add stage
          </Button>
        </CardContent>
      </Card>

      {removedStageIds.length > 0 && (
        <WarningCallout>
          Removing: {removedStageIds.join(', ')}. Any interests parked on these stages will need to
          be reassigned before save.
        </WarningCallout>
      )}

      <div className="flex items-center gap-3">
        <Button onClick={() => attemptSave(false)} disabled={saving}>
          {saving ? (
            <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />
          ) : (
            <Save className="mr-1.5 h-4 w-4" aria-hidden />
          )}
          Save stages
        </Button>
      </div>

      <Dialog open={!!reassignDialog} onOpenChange={(o) => !o && setReassignDialog(null)}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>Reassign interests</DialogTitle>
            <DialogDescription>
              These residential interests sit on a stage you&apos;re removing. Pick a new stage for
              each before saving.
            </DialogDescription>
          </DialogHeader>
          {reassignDialog && (
            <div className="space-y-3 max-h-80 overflow-y-auto">
              {reassignDialog.affected.map((o) => (
                <div key={o.id} className="flex items-center justify-between gap-3 text-sm">
                  <div className="min-w-0">
                    <code className="text-xs">{o.id.slice(0, 12)}…</code>
                    <p className="text-xs text-muted-foreground">
                      currently: <code className="text-xs">{o.pipelineStage}</code>
                    </p>
                  </div>
                  <Select
                    value={reassignDialog.reassignments[o.id] ?? ''}
                    onValueChange={(v) =>
                      setReassignDialog((prev) =>
                        prev
                          ? {
                              ...prev,
                              reassignments: { ...prev.reassignments, [o.id]: v },
                            }
                          : prev,
                      )
                    }
                  >
                    <SelectTrigger className="w-44 h-8">
                      <SelectValue placeholder="Choose stage…" />
                    </SelectTrigger>
                    <SelectContent>
                      {stages.map((s) => (
                        <SelectItem key={s.id} value={s.id}>
                          {s.label}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
              ))}
            </div>
          )}
          <DialogFooter>
            <Button variant="outline" onClick={() => setReassignDialog(null)}>
              Cancel
            </Button>
            <Button
              onClick={() => {
                if (!reassignDialog) return;
                const allAssigned = reassignDialog.affected.every(
                  (o) => reassignDialog.reassignments[o.id],
                );
                if (!allAssigned) {
                  toast.error('Pick a new stage for every listed interest first.');
                  return;
                }
                void attemptSave(true, reassignDialog.reassignments);
              }}
              disabled={saving}
            >
              {saving && <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />}
              Reassign + save
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
