"use client";

import { useState, useMemo, useEffect } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { AlertTriangle, Loader2 } from "lucide-react";
import { MEASURE_NAMES } from "@/app/lib/measureDocumentRequirements";
import { useToast } from "@/app/hooks/use-toast";

interface InstructMeasureEditorProps {
  dealId: string;
  portfolioId: string;
  proposedMeasures: string[];
  canEdit: boolean;
  outOfOrderWarning: string | null;
  onSuccess?: () => void;
}

export function InstructMeasureEditor({
  dealId,
  portfolioId,
  proposedMeasures,
  canEdit,
  outOfOrderWarning,
  onSuccess,
}: InstructMeasureEditorProps) {
  const queryClient = useQueryClient();
  const { toast } = useToast();

  const { data: pibiData } = useQuery<{
    pibiMeasures: string[];
    approvedMeasures: string[];
    instructedMeasures: string[];
  }>({
    queryKey: ["pibiMeasures", portfolioId, dealId],
    queryFn: async () => {
      const res = await fetch(
        `/api/portfolio/${portfolioId}/pibi-measures?dealId=${encodeURIComponent(dealId)}`,
      );
      if (!res.ok) throw new Error("Failed to fetch measures");
      return res.json();
    },
    staleTime: 30_000,
    enabled: canEdit,
  });

  const excluded = useMemo(() => {
    const set = new Set<string>(proposedMeasures);
    for (const m of pibiData?.approvedMeasures ?? []) set.add(m);
    for (const m of pibiData?.instructedMeasures ?? []) set.add(m);
    return set;
  }, [proposedMeasures, pibiData]);

  const eligible = useMemo(
    () => MEASURE_NAMES.filter((m) => !excluded.has(m)),
    [excluded],
  );

  const [checked, setChecked] = useState<Set<string>>(new Set());
  const [confirmText, setConfirmText] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    setChecked(new Set());
    setConfirmText("");
    setError(null);
  }, [dealId]);

  if (!canEdit) return null;

  function toggleMeasure(m: string) {
    setChecked((prev) => {
      const next = new Set(prev);
      if (next.has(m)) next.delete(m);
      else next.add(m);
      return next;
    });
  }

  async function handleSubmit() {
    const measureNames = Array.from(checked);
    if (measureNames.length === 0 || confirmText !== "confirm") return;
    setSubmitting(true);
    setError(null);
    try {
      const res = await fetch(
        `/api/portfolio/${portfolioId}/instructed-measures`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ dealId, measureNames }),
        },
      );
      if (!res.ok) {
        const json = await res.json().catch(() => ({}));
        setError(
          typeof json.error === "string"
            ? json.error
            : "Failed to instruct measures",
        );
        return;
      }
      const json = (await res.json()) as {
        ok: boolean;
        hubspotSync: "ok" | "failed";
        hubspotError?: string;
      };
      setChecked(new Set());
      setConfirmText("");
      void queryClient.invalidateQueries({ queryKey: ["pibiMeasures", portfolioId, dealId] });
      onSuccess?.();
      if (json.hubspotSync === "failed") {
        toast({
          title: "Measures instructed",
          description: json.hubspotError
            ? `Saved locally — HubSpot sync failed: ${json.hubspotError}`
            : "Saved locally — HubSpot sync failed",
          variant: "destructive",
        });
      } else {
        toast({
          title: "Measures instructed",
          description: `${measureNames.join(", ")} ${measureNames.length === 1 ? "has" : "have"} been instructed.`,
        });
      }
    } catch (err) {
      setError(
        err instanceof Error ? err.message : "Failed to instruct measures",
      );
    } finally {
      setSubmitting(false);
    }
  }

  const hasSelection = checked.size > 0;
  const canSubmit = hasSelection && confirmText === "confirm" && !submitting;

  return (
    <div className="space-y-3">
      {outOfOrderWarning && (
        <div
          data-testid="instruct-measure-warning"
          className="flex items-start gap-2 text-xs text-amber-800 bg-amber-50 border border-amber-200 px-3 py-2 rounded-lg"
        >
          <AlertTriangle className="h-3.5 w-3.5 mt-0.5 shrink-0" />
          <span>{outOfOrderWarning}</span>
        </div>
      )}
      <div className="flex flex-col gap-1">
        <span className="text-xs text-gray-500 font-medium">Instruct measures</span>
        {eligible.length === 0 ? (
          <p className="text-xs text-gray-400 italic">All measures already proposed or approved.</p>
        ) : (
          <div
            data-testid="instruct-measure-checklist"
            className="flex flex-col gap-0.5 max-h-48 overflow-y-auto rounded-lg border border-gray-200 p-2"
          >
            {eligible.map((m) => (
              <label
                key={m}
                className="flex items-center gap-2 px-2 py-1 rounded cursor-pointer hover:bg-gray-50 text-xs text-gray-800"
              >
                <input
                  type="checkbox"
                  checked={checked.has(m)}
                  onChange={() => toggleMeasure(m)}
                  disabled={submitting}
                  className="accent-brandblue"
                />
                {m}
              </label>
            ))}
          </div>
        )}
      </div>

      {hasSelection && (
        <div className="space-y-2 border-t border-gray-100 pt-3">
          <div className="flex flex-wrap gap-1">
            {Array.from(checked).map((m) => (
              <span
                key={m}
                className="px-2 py-0.5 rounded-full text-[11px] bg-blue-50 border border-blue-200 text-blue-700"
              >
                {m}
              </span>
            ))}
          </div>
          <label className="flex flex-col gap-1">
            <span className="text-xs text-gray-500">
              Type <span className="font-mono font-semibold">confirm</span> to instruct
            </span>
            <input
              data-testid="instruct-measure-confirm-input"
              type="text"
              value={confirmText}
              onChange={(e) => setConfirmText(e.target.value)}
              disabled={submitting}
              placeholder="confirm"
              className="rounded-lg border border-gray-200 px-3 py-1.5 text-xs text-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-300 w-full"
            />
          </label>
          <button
            type="button"
            data-testid="instruct-measure-submit"
            onClick={handleSubmit}
            disabled={!canSubmit}
            className="flex items-center gap-1.5 text-xs font-medium px-3 py-1.5 rounded-lg bg-brandblue text-white hover:bg-brandmidblue disabled:opacity-50 transition-colors"
          >
            {submitting && <Loader2 className="h-3.5 w-3.5 animate-spin" />}
            {submitting ? "Instructing…" : `Instruct ${checked.size} measure${checked.size === 1 ? "" : "s"}`}
          </button>
        </div>
      )}

      {error && (
        <p
          data-testid="instruct-measure-error"
          className="text-xs text-red-600 bg-red-50 px-3 py-2 rounded-lg"
        >
          {error}
        </p>
      )}
    </div>
  );
}
