import { useState, useEffect, useMemo } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { Input } from '@/components/ui/input';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Loader2, GitMerge, AlertTriangle, Search } from 'lucide-react';
import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/components/ui/use-toast';
import { formatShortDateEST } from '@/lib/timezoneUtils';

/**
 * Merge prior violations into the currently-open (newest) violation.
 * - Combines timeline entries (deduped by id/date+description)
 * - Merges photo_urls
 * - Appends prior descriptions/notes into notes
 * - Optionally archives merged source violations
 */
export default function ViolationMergeDialog({ open, onOpenChange, violation, onSuccess }) {
  const { toast } = useToast();
  const [candidates, setCandidates] = useState([]);
  const [loading, setLoading] = useState(false);
  const [merging, setMerging] = useState(false);
  const [selected, setSelected] = useState({});
  const [archiveSources, setArchiveSources] = useState(true);
  const [search, setSearch] = useState('');

  useEffect(() => {
    if (!open || !violation?.id) return;
    setSelected({});
    setSearch('');
    fetchCandidates();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, violation?.id]);

  const fetchCandidates = async () => {
    setLoading(true);
    try {
      let query = supabase
        .from('violations')
        .select('id, title, violation_type, address, status, stage, created_at, violation_date, owner_id, unit_id, description, notes, timeline_entries, photo_urls, photo_url')
        .eq('association_id', violation.association_id)
        .neq('id', violation.id)
        .order('created_at', { ascending: false })
        .limit(200);

      // Prefer matching by unit, then owner, then address
      if (violation.unit_id) query = query.eq('unit_id', violation.unit_id);
      else if (violation.owner_id) query = query.eq('owner_id', violation.owner_id);
      else if (violation.address) query = query.eq('address', violation.address);

      const { data, error } = await query;
      if (error) throw error;
      setCandidates(data || []);
    } catch (err) {
      toast({ variant: 'destructive', title: 'Failed to load violations', description: err.message });
    } finally {
      setLoading(false);
    }
  };

  const filtered = useMemo(() => {
    if (!search.trim()) return candidates;
    const q = search.toLowerCase();
    return candidates.filter(c =>
      (c.title || '').toLowerCase().includes(q) ||
      (c.violation_type || '').toLowerCase().includes(q) ||
      (c.address || '').toLowerCase().includes(q) ||
      (c.description || '').toLowerCase().includes(q)
    );
  }, [candidates, search]);

  const selectedIds = Object.keys(selected).filter(id => selected[id]);

  const toggleAll = (val) => {
    const next = {};
    if (val) filtered.forEach(c => { next[c.id] = true; });
    setSelected(next);
  };

  const handleMerge = async () => {
    if (selectedIds.length === 0) {
      toast({ variant: 'destructive', title: 'Select at least one violation to merge' });
      return;
    }
    setMerging(true);
    try {
      const sources = candidates.filter(c => selectedIds.includes(c.id));

      // Combine timeline entries
      const existingTimeline = Array.isArray(violation.timeline_entries) ? [...violation.timeline_entries] : [];
      const seenKeys = new Set(
        existingTimeline.map(e => `${e.id || ''}|${e.date || ''}|${(e.description || '').slice(0, 60)}`)
      );
      const mergedTimeline = [...existingTimeline];

      // Combine photos (normalize to {url, timestamp})
      const normalizePhotos = (v) => {
        if (Array.isArray(v.photo_urls) && v.photo_urls.length) {
          return v.photo_urls.map(p => typeof p === 'string' ? { url: p } : p);
        }
        if (v.photo_url) return [{ url: v.photo_url }];
        return [];
      };
      const existingPhotos = normalizePhotos(violation);
      const seenPhotoUrls = new Set(existingPhotos.map(p => p.url));
      const mergedPhotos = [...existingPhotos];

      const noteAdditions = [];

      for (const src of sources) {
        const srcEntries = Array.isArray(src.timeline_entries) ? src.timeline_entries : [];
        for (const entry of srcEntries) {
          const key = `${entry.id || ''}|${entry.date || ''}|${(entry.description || '').slice(0, 60)}`;
          if (!seenKeys.has(key)) {
            mergedTimeline.push({
              ...entry,
              merged_from_violation_id: src.id,
            });
            seenKeys.add(key);
          }
        }

        for (const photo of normalizePhotos(src)) {
          if (photo.url && !seenPhotoUrls.has(photo.url)) {
            mergedPhotos.push(photo);
            seenPhotoUrls.add(photo.url);
          }
        }

        const dateLabel = src.violation_date || src.created_at;
        const header = `--- Merged from violation ${formatShortDateEST(dateLabel)} (${src.violation_type || src.title || 'Violation'}) ---`;
        const body = [src.description, src.notes].filter(Boolean).join('\n');
        if (body) noteAdditions.push(`${header}\n${body}`);
      }

      // Sort timeline ascending by date
      mergedTimeline.sort((a, b) => new Date(a.date || 0) - new Date(b.date || 0));

      const combinedNotes = [violation.notes || '', ...noteAdditions].filter(Boolean).join('\n\n');

      const updatePayload = {
        timeline_entries: mergedTimeline,
        photo_urls: mergedPhotos,
        photo_url: mergedPhotos[0]?.url || violation.photo_url || null,
        notes: combinedNotes || null,
        updated_at: new Date().toISOString(),
      };

      const { error: updateErr } = await supabase
        .from('violations')
        .update(updatePayload)
        .eq('id', violation.id);
      if (updateErr) throw updateErr;

      if (archiveSources) {
        const { error: archiveErr } = await supabase
          .from('violations')
          .update({ status: 'resolved', stage: 'Merged', updated_at: new Date().toISOString() })
          .in('id', selectedIds);
        if (archiveErr) throw archiveErr;
      }

      toast({
        title: 'Merge Complete',
        description: `Merged ${selectedIds.length} violation(s) into the current record.`,
      });
      onOpenChange(false);
      if (onSuccess) onSuccess();
    } catch (err) {
      toast({ variant: 'destructive', title: 'Merge Failed', description: err.message });
    } finally {
      setMerging(false);
    }
  };

  const allSelected = filtered.length > 0 && filtered.every(c => selected[c.id]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-[750px] max-h-[85vh] flex flex-col">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <GitMerge className="w-5 h-5 text-primary" /> Merge Violations
          </DialogTitle>
          <DialogDescription>
            Select prior violations for this {violation?.unit_id ? 'unit' : violation?.owner_id ? 'owner' : 'address'} to merge their timeline history, photos, and notes into the current violation.
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-3 flex-1 overflow-hidden flex flex-col">
          <div className="bg-muted/40 border rounded-md p-3 text-xs space-y-1">
            <div className="font-semibold flex items-center gap-2">
              <AlertTriangle className="w-3.5 h-3.5 text-amber-600" /> Target (current) violation
            </div>
            <div className="text-muted-foreground">
              {violation?.violation_type || violation?.title || 'Violation'} · {violation?.address || '—'} · {formatShortDateEST(violation?.violation_date || violation?.created_at)}
            </div>
          </div>

          <div className="relative">
            <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
            <Input
              placeholder="Search candidates..."
              className="pl-9"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
            />
          </div>

          {loading ? (
            <div className="flex justify-center py-12"><Loader2 className="w-6 h-6 animate-spin text-muted-foreground" /></div>
          ) : filtered.length === 0 ? (
            <div className="text-center py-12 text-muted-foreground text-sm border rounded-md">
              No prior violations found for this {violation?.unit_id ? 'unit' : violation?.owner_id ? 'owner' : 'address'}.
            </div>
          ) : (
            <>
              <div className="flex items-center justify-between text-xs px-1">
                <label className="flex items-center gap-2 cursor-pointer">
                  <Checkbox checked={allSelected} onCheckedChange={(v) => toggleAll(!!v)} />
                  <span>Select all ({filtered.length})</span>
                </label>
                <span className="text-muted-foreground">{selectedIds.length} selected</span>
              </div>
              <ScrollArea className="flex-1 border rounded-md">
                <div className="divide-y">
                  {filtered.map((c) => {
                    const entryCount = Array.isArray(c.timeline_entries) ? c.timeline_entries.length : 0;
                    const photoCount = Array.isArray(c.photo_urls) ? c.photo_urls.length : (c.photo_url ? 1 : 0);
                    return (
                      <label key={c.id} className="flex items-start gap-3 p-3 hover:bg-muted/40 cursor-pointer">
                        <Checkbox
                          checked={!!selected[c.id]}
                          onCheckedChange={(v) => setSelected(prev => ({ ...prev, [c.id]: !!v }))}
                          className="mt-0.5"
                        />
                        <div className="flex-1 min-w-0">
                          <div className="flex items-center gap-2 flex-wrap">
                            <span className="font-medium text-sm truncate">{c.violation_type || c.title || 'Violation'}</span>
                            <Badge variant="outline" className="text-[10px] capitalize">{c.status || 'open'}</Badge>
                            {c.stage && <Badge variant="secondary" className="text-[10px]">{c.stage}</Badge>}
                          </div>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            {formatShortDateEST(c.violation_date || c.created_at)}
                            {c.address && ` · ${c.address}`}
                          </p>
                          <div className="text-[11px] text-muted-foreground mt-1 flex gap-3">
                            <span>{entryCount} timeline {entryCount === 1 ? 'entry' : 'entries'}</span>
                            <span>{photoCount} photo{photoCount === 1 ? '' : 's'}</span>
                          </div>
                        </div>
                      </label>
                    );
                  })}
                </div>
              </ScrollArea>
            </>
          )}

          <label className="flex items-center gap-2 text-sm pt-1">
            <Checkbox checked={archiveSources} onCheckedChange={(v) => setArchiveSources(!!v)} />
            <span>Mark merged violations as resolved (stage: Merged)</span>
          </label>
        </div>

        <DialogFooter className="pt-3 border-t">
          <Button variant="outline" onClick={() => onOpenChange(false)} disabled={merging}>Cancel</Button>
          <Button onClick={handleMerge} disabled={merging || selectedIds.length === 0}>
            {merging ? <Loader2 className="w-4 h-4 mr-2 animate-spin" /> : <GitMerge className="w-4 h-4 mr-2" />}
            Merge {selectedIds.length > 0 ? `${selectedIds.length} ` : ''}Violation{selectedIds.length === 1 ? '' : 's'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
