"use client";

/**
 * Discover Competitors card
 * ──────────────────────────
 * Two buttons (Local / National) that hit POST /api/competitors/discover.
 * Returned candidates render as a checkbox list with overlap badges
 * + SERP-provider-validated keyword overlap counts. User picks the ones
 * they want, clicks "Add Selected", and we fan out to the existing
 * POST /api/competitors/add (which runs the initial sitemap crawl).
 *
 * Multi-location: when the brand has 2+ locations the "Discover Local"
 * button opens an inline picker instead of immediately running. Up to 3
 * locations can be selected per run (hard cap, enforced client + server).
 *
 * Shown above the competitor list when the brand has 0-2 competitors,
 * or by manually clicking "Discover more" when more are tracked.
 */

import { useState, useEffect } from "react";
import { Sparkles, Loader2, Plus, MapPin, Globe, CheckCircle2, Info, AlertTriangle, X } from "lucide-react";
import Link from "next/link";

interface Discovered {
  domain: string;
  name: string;
  type: "DIRECT" | "NATIONAL" | "ADJACENT" | "UNKNOWN";
  overlap: "HIGH" | "MEDIUM" | "LOW";
  reason: string;
  validatedOverlapCount: number | null;
  validation: "confirmed" | "unverified" | "skipped";
  validationNote: string;
  alreadyTracked: boolean;
  discoveredForLocations?: string[];
}

interface Props {
  brandId: string;
  /** Called after candidates are added so the parent can refresh the list. */
  onAdded: () => void;
  /** Optional click-to-toast surface used elsewhere on the page. */
  onMessage?: (msg: string) => void;
}

// Overlap bucket is an AI-assigned signal, not a toxicity indicator —
// never use red. HIGH = emerald, MEDIUM = amber, LOW = slate.
const OVERLAP_BADGE: Record<Discovered["overlap"], string> = {
  HIGH:   "bg-emerald-50 text-emerald-700 border-emerald-200",
  MEDIUM: "bg-amber-50 text-amber-700 border-amber-200",
  LOW:    "bg-slate-50 text-slate-600 border-slate-200",
};

const TYPE_BADGE: Record<Discovered["type"], string> = {
  DIRECT:   "bg-blue-50 text-blue-700",
  NATIONAL: "bg-violet-50 text-violet-700",
  ADJACENT: "bg-slate-50 text-slate-600",
  UNKNOWN:  "bg-slate-50 text-slate-500",
};

// Sync path cap — 1-3 locations run immediately; 4+ queue via background job.
const SYNC_MAX_LOCATIONS = 3;

interface JobStatus {
  id: string;
  status: string;
  totalLocations: number;
  processedLocations: number;
  competitorsFound: number;
  error?: string | null;
}

export default function DiscoverCompetitors({ brandId, onAdded, onMessage }: Props) {
  const [loading, setLoading] = useState(false);
  const [adding, setAdding] = useState(false);
  const [candidates, setCandidates] = useState<Discovered[]>([]);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [error, setError] = useState<string | null>(null);
  const [costUsd, setCostUsd] = useState<number | null>(null);
  const [locationsRun, setLocationsRun] = useState<string[]>([]);

  // Brand locations — fetched once on mount from the brand-profile endpoint.
  const [brandLocations, setBrandLocations] = useState<string[]>([]);
  const [locationsLoaded, setLocationsLoaded] = useState(false);

  // Location picker state (shown when brand has 2+ locations and user
  // clicks "Discover Local Competitors").
  const [pickerOpen, setPickerOpen] = useState(false);
  const [pickerSelected, setPickerSelected] = useState<Set<string>>(new Set());

  // Async job state — used when 4+ locations are selected.
  const [jobId, setJobId] = useState<string | null>(null);
  const [jobStatus, setJobStatus] = useState<JobStatus | null>(null);

  useEffect(() => {
    fetch(`/api/content-briefs/brand-profile?brandId=${brandId}`)
      .then((r) => r.ok ? r.json() : null)
      .then((data) => {
        if (data?.locations && Array.isArray(data.locations)) {
          setBrandLocations(data.locations.filter((l: unknown): l is string => typeof l === "string" && l.trim() !== ""));
        }
        setLocationsLoaded(true);
      })
      .catch(() => setLocationsLoaded(true));
  }, [brandId]);

  // Poll async job every 5 seconds until completed or failed.
  useEffect(() => {
    if (!jobId) return;
    const interval = setInterval(async () => {
      try {
        const res = await fetch(`/api/competitors/jobs/${jobId}`);
        const data: JobStatus = await res.json();
        setJobStatus(data);
        if (data.status === "completed" || data.status === "failed") {
          clearInterval(interval);
          if (data.status === "completed") {
            setPickerOpen(false);
            onAdded();
            onMessage?.(`Background discovery complete — ${data.competitorsFound} competitors found across ${data.totalLocations} locations. Refresh to add them.`);
          }
        }
      } catch { /* network blip — keep polling */ }
    }, 5000);
    return () => clearInterval(interval);
  }, [jobId]); // eslint-disable-line react-hooks/exhaustive-deps

  async function discover(focus: "local" | "national", locations?: string[]) {
    setLoading(true);
    setError(null);
    setCandidates([]);
    setSelected(new Set());
    setLocationsRun([]);
    setPickerOpen(false);
    try {
      const res = await fetch("/api/competitors/discover", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ brandId, focus, ...(locations ? { locations } : {}) }),
      });
      const data = await res.json();
      if (!res.ok) {
        setError(data.error ?? "Discovery failed");
      } else {
        setCandidates(data.candidates ?? []);
        setCostUsd(data.costUsd ?? 0);
        setLocationsRun(data.locationsRun ?? []);
        const preselected = new Set<string>(
          (data.candidates as Discovered[])
            .filter((c) => !c.alreadyTracked && c.validation === "confirmed")
            .map((c) => c.domain),
        );
        setSelected(preselected);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "Network error");
    } finally {
      setLoading(false);
    }
  }

  function handleLocalClick() {
    if (brandLocations.length === 0) {
      setError("no_location");
      return;
    }
    if (brandLocations.length === 1) {
      discover("local", [brandLocations[0]]);
      return;
    }
    // 2+ locations — open inline picker with all locations pre-checked.
    setPickerSelected(new Set(brandLocations));
    setPickerOpen(true);
  }

  function togglePickerLocation(loc: string) {
    setPickerSelected((prev) => {
      const next = new Set(prev);
      next.has(loc) ? next.delete(loc) : next.add(loc);
      return next;
    });
  }

  async function handlePickerSubmit(selectedArr: string[]) {
    if (selectedArr.length === 0) return;
    setPickerOpen(false);
    if (selectedArr.length <= SYNC_MAX_LOCATIONS) {
      // Sync path — runs immediately, results shown inline.
      discover("local", selectedArr);
    } else {
      // Async path — create a background job, poll for progress.
      setError(null);
      setJobId(null);
      setJobStatus(null);
      try {
        const res = await fetch("/api/competitors/discover-async", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ brandId, focus: "local", locations: selectedArr, limit: 20 }),
        });
        const data = await res.json();
        if (!res.ok) {
          setError(data.error ?? "Failed to queue discovery");
        } else {
          setJobId(data.jobId);
          setJobStatus({ id: data.jobId, status: "pending", totalLocations: data.totalLocations, processedLocations: 0, competitorsFound: 0 });
        }
      } catch (err) {
        setError(err instanceof Error ? err.message : "Network error");
      }
    }
  }

  function toggle(domain: string) {
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(domain) ? next.delete(domain) : next.add(domain);
      return next;
    });
  }

  async function addSelected() {
    if (selected.size === 0 || adding) return;
    setAdding(true);
    try {
      const additions = candidates.filter((c) => selected.has(c.domain));
      let added = 0;
      for (const c of additions) {
        const res = await fetch("/api/competitors/add", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            brandId,
            domain: c.domain,
            name: c.name,
            discoveredForLocations: c.discoveredForLocations ?? [],
          }),
        });
        if (res.ok) added++;
      }
      onMessage?.(`Added ${added} competitor${added === 1 ? "" : "s"} — initial crawl${added === 1 ? "" : "s"} running.`);
      setCandidates([]);
      setSelected(new Set());
      onAdded();
    } finally {
      setAdding(false);
    }
  }

  // ── Async job progress UI ────────────────────────────────────────
  if (jobId && jobStatus && jobStatus.status !== "completed" && jobStatus.status !== "failed" && candidates.length === 0) {
    const pct = jobStatus.totalLocations > 0
      ? Math.round((jobStatus.processedLocations / jobStatus.totalLocations) * 100)
      : 0;
    return (
      <div className="bg-gradient-to-br from-violet-50 to-blue-50 rounded-xl border border-violet-200 p-5">
        <div className="flex items-start gap-3 mb-3">
          <Loader2 className="w-5 h-5 text-violet-600 mt-0.5 animate-spin shrink-0" />
          <div>
            <h3 className="font-bold text-slate-900 text-sm">Discovery in progress</h3>
            <p className="text-xs text-slate-600 mt-0.5">
              {jobStatus.processedLocations} of {jobStatus.totalLocations} locations processed
            </p>
          </div>
        </div>
        <div className="h-2 rounded-full bg-slate-200 mb-2">
          <div
            className="h-full rounded-full bg-violet-500 transition-all duration-500"
            style={{ width: `${pct}%` }}
          />
        </div>
        <p className="text-[11px] text-slate-500">
          {jobStatus.competitorsFound} competitors found so far · ~1 min per remaining location
        </p>
      </div>
    );
  }

  if (jobStatus?.status === "failed" && candidates.length === 0) {
    return (
      <div className="bg-red-50 rounded-xl border border-red-200 p-5">
        <div className="flex items-center gap-2 text-red-700 text-sm font-semibold">
          <AlertTriangle className="w-4 h-4" /> Background discovery failed
        </div>
        <p className="text-xs text-red-600 mt-1">{jobStatus.error ?? "An error occurred while processing a location."}</p>
        <button
          onClick={() => { setJobId(null); setJobStatus(null); setError(null); }}
          className="mt-3 px-3 py-1.5 text-xs bg-white border border-red-200 text-red-700 rounded-lg font-semibold hover:bg-red-100"
        >
          Try again
        </button>
      </div>
    );
  }

  // ── Idle / starting state ────────────────────────────────────────
  if (candidates.length === 0 && !loading && !error && !pickerOpen) {
    return (
      <div className="bg-gradient-to-br from-violet-50 to-blue-50 rounded-xl border border-violet-200 p-5">
        <div className="flex items-start gap-3 mb-3">
          <Sparkles className="w-5 h-5 text-violet-600 mt-0.5" />
          <div>
            <h3 className="font-bold text-slate-900 text-sm">Discover Competitors</h3>
            <p className="text-xs text-slate-600 mt-0.5">
              AI suggests likely competitors from your industry, location, and top GSC keywords —
              then live SERP data validates each by counting real keyword overlap.
            </p>
          </div>
        </div>
        <div className="flex gap-2">
          <button
            onClick={handleLocalClick}
            className="flex items-center gap-1.5 px-4 py-2 bg-white border border-violet-200 text-violet-700 text-xs font-semibold rounded-lg hover:bg-violet-100"
          >
            <MapPin className="w-3.5 h-3.5" /> Discover Local Competitors
          </button>
          <button
            onClick={() => discover("national")}
            className="flex items-center gap-1.5 px-4 py-2 bg-white border border-violet-200 text-violet-700 text-xs font-semibold rounded-lg hover:bg-violet-100"
          >
            <Globe className="w-3.5 h-3.5" /> Find National Competitors
          </button>
        </div>

        {error === "no_location" && locationsLoaded && (
          <div className="mt-3 flex items-start gap-2 text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2">
            <AlertTriangle className="w-3.5 h-3.5 shrink-0 mt-0.5" />
            <span>
              Add a location to your brand profile to use local discovery.{" "}
              <Link href={`/brands/${brandId}/edit`} className="underline font-semibold">Edit profile →</Link>
            </span>
          </div>
        )}
      </div>
    );
  }

  // ── Location picker (inline expand for 2+ locations) ─────────────
  if (pickerOpen && !loading) {
    const selectedArr = Array.from(pickerSelected);
    const isAsync = selectedArr.length > SYNC_MAX_LOCATIONS;
    const estimatedCostPerLoc = 0.20;
    const estimatedTotal = (selectedArr.length * estimatedCostPerLoc).toFixed(2);
    return (
      <div className="bg-gradient-to-br from-violet-50 to-blue-50 rounded-xl border border-violet-200 p-5">
        <div className="flex items-start justify-between mb-3">
          <div className="flex items-start gap-3">
            <MapPin className="w-5 h-5 text-violet-600 mt-0.5 shrink-0" />
            <div>
              <h3 className="font-bold text-slate-900 text-sm">Select locations to search</h3>
              <p className="text-xs text-slate-600 mt-0.5">
                {isAsync
                  ? `${selectedArr.length} locations selected — will run as a background job (~1 min per location).`
                  : "We run a separate pass per location and combine results."}
              </p>
            </div>
          </div>
          <button onClick={() => setPickerOpen(false)} className="text-slate-400 hover:text-slate-600">
            <X className="w-4 h-4" />
          </button>
        </div>

        <ul className="space-y-1.5 mb-3">
          {brandLocations.map((loc) => {
            const checked = pickerSelected.has(loc);
            return (
              <li key={loc}>
                <label className="flex items-center gap-2.5 px-3 py-2 bg-white rounded-lg border border-slate-200 cursor-pointer hover:border-violet-300 text-sm text-slate-800">
                  <input
                    type="checkbox"
                    checked={checked}
                    onChange={() => togglePickerLocation(loc)}
                    className="rounded"
                  />
                  {loc}
                </label>
              </li>
            );
          })}
        </ul>

        {isAsync && (
          <p className="text-[11px] text-blue-700 bg-blue-50 border border-blue-200 rounded px-2 py-1.5 mb-3">
            4+ locations will queue as a background job. Results appear automatically as each location finishes.
          </p>
        )}

        <div className="flex items-center justify-between text-[11px] text-slate-500 mb-3">
          <span>{selectedArr.length} of {brandLocations.length} selected</span>
          <span>~${estimatedCostPerLoc.toFixed(2)} per location · estimated total: ~${estimatedTotal} for {selectedArr.length}</span>
        </div>

        <div className="flex items-center gap-2">
          <button
            onClick={() => setPickerOpen(false)}
            className="px-3 py-1.5 text-xs text-slate-500 hover:text-slate-700 border border-slate-200 bg-white rounded-lg"
          >
            Cancel
          </button>
          <button
            onClick={() => handlePickerSubmit(selectedArr)}
            disabled={selectedArr.length === 0}
            className="flex items-center gap-1.5 px-4 py-1.5 bg-violet-600 text-white text-xs font-semibold rounded-lg hover:bg-violet-700 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <MapPin className="w-3.5 h-3.5" />
            {isAsync ? `Queue ${selectedArr.length} locations →` : `Run for ${selectedArr.length} location${selectedArr.length === 1 ? "" : "s"} →`}
          </button>
        </div>
      </div>
    );
  }

  if (loading) {
    const runningFor = pickerSelected.size > 1
      ? `Running discovery for ${pickerSelected.size} locations…`
      : "Discovering competitors and validating with live SERP data…";
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-8 flex items-center justify-center text-slate-500 text-sm">
        <Loader2 className="w-4 h-4 animate-spin mr-2" />
        {runningFor} (~10-30s per location)
      </div>
    );
  }

  if (error && error !== "no_location") {
    return (
      <div className="bg-red-50 rounded-xl border border-red-200 p-5">
        <div className="flex items-center gap-2 text-red-700 text-sm font-semibold">
          <AlertTriangle className="w-4 h-4" /> Discovery failed
        </div>
        <p className="text-xs text-red-600 mt-1">{error}</p>
        <button
          onClick={() => { setError(null); }}
          className="mt-3 px-3 py-1.5 text-xs bg-white border border-red-200 text-red-700 rounded-lg font-semibold hover:bg-red-100"
        >
          Try again
        </button>
      </div>
    );
  }

  // ── Results state ────────────────────────────────────────────────
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <div className="px-5 py-3.5 border-b border-slate-100 flex items-center justify-between">
        <div className="flex items-center gap-2 flex-wrap">
          <Sparkles className="w-4 h-4 text-violet-600" />
          <h3 className="font-bold text-slate-800 text-sm">{candidates.length} Competitors Discovered</h3>
          {locationsRun.length > 1 && (
            <span className="text-[10px] text-violet-600 font-semibold bg-violet-50 border border-violet-200 rounded px-1.5 py-0.5">
              {locationsRun.length} locations
            </span>
          )}
          {costUsd != null && costUsd > 0 && (
            <span className="text-[10px] text-slate-400">SERP lookup cost: ${costUsd.toFixed(2)}</span>
          )}
        </div>
        <button
          onClick={() => { setCandidates([]); setSelected(new Set()); setLocationsRun([]); }}
          className="text-[11px] text-slate-500 hover:text-slate-700"
        >
          Clear
        </button>
      </div>

      <ul className="divide-y divide-slate-100">
        {candidates.map((c) => (
          <li key={c.domain} className="px-5 py-3 flex items-start gap-3">
            <input
              type="checkbox"
              checked={selected.has(c.domain)}
              onChange={() => toggle(c.domain)}
              disabled={c.alreadyTracked}
              className="mt-1 rounded shrink-0"
            />
            <div className="flex-1 min-w-0">
              <div className="flex items-center gap-2 flex-wrap">
                <span className="font-semibold text-sm text-slate-900">{c.domain}</span>
                <span className={`px-1.5 py-0.5 rounded text-[9px] font-bold uppercase tracking-wide ${TYPE_BADGE[c.type]}`}>
                  {c.type}
                </span>
                <span className={`px-1.5 py-0.5 rounded text-[9px] font-bold uppercase tracking-wide border ${OVERLAP_BADGE[c.overlap]}`}>
                  {c.overlap.toLowerCase()} overlap
                </span>
                {c.alreadyTracked ? (
                  <span className="inline-flex items-center gap-1 text-[10px] text-emerald-600 font-semibold">
                    <CheckCircle2 className="w-3 h-3" /> Already tracked
                  </span>
                ) : c.validation === "confirmed" && c.validatedOverlapCount != null && c.validatedOverlapCount > 0 ? (
                  <span className="inline-flex items-center gap-1 text-[10px] text-emerald-700 font-semibold bg-emerald-50 border border-emerald-200 rounded px-1.5 py-0.5">
                    <CheckCircle2 className="w-3 h-3" /> {c.validatedOverlapCount} shared keyword{c.validatedOverlapCount === 1 ? "" : "s"}
                  </span>
                ) : c.validation === "unverified" ? (
                  <span className="inline-flex items-center gap-1 text-[10px] text-slate-500 font-semibold bg-slate-100 border border-slate-200 rounded px-1.5 py-0.5">
                    <Info className="w-3 h-3" /> AI identified
                  </span>
                ) : null}
              </div>
              <p className="text-sm text-slate-700 mt-1">&quot;{c.reason}&quot;</p>
              {c.validationNote && (
                <p className="text-[11px] text-slate-500 mt-1">{c.validationNote}</p>
              )}
              {c.discoveredForLocations && c.discoveredForLocations.length > 0 && (
                <p className="text-[10px] text-violet-600 mt-1 flex items-center gap-1">
                  <MapPin className="w-2.5 h-2.5 shrink-0" />
                  Found in: {c.discoveredForLocations.join(" · ")}
                </p>
              )}
            </div>
          </li>
        ))}
      </ul>

      <div className="px-5 py-3 border-t border-slate-100 flex items-center justify-between bg-slate-50/60">
        <p className="text-xs text-slate-500">
          {selected.size > 0 ? `${selected.size} selected` : "Pick competitors to start tracking"}
        </p>
        <button
          onClick={addSelected}
          disabled={selected.size === 0 || adding}
          className="flex items-center gap-1.5 px-4 py-2 bg-brand-600 text-white text-xs font-semibold rounded-lg hover:bg-brand-700 disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {adding ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />}
          Add {selected.size > 0 ? selected.size : ""} Competitor{selected.size === 1 ? "" : "s"}
        </button>
      </div>
    </div>
  );
}
