import { useRef, useState } from "react";
import ReactCrop, { Crop, PixelCrop, centerCrop, makeAspectCrop } from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { Camera, Copy, Plus, RotateCcw, Save, Sparkles, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { useToast } from "@/hooks/use-toast";
import { apiRequest } from "@/lib/queryClient";
import { PatientTable } from "@/components/patients/patient-table";
import { Patient } from "@repo/db/types";

function getCroppedDataUrl(image: HTMLImageElement, crop: PixelCrop): string {
  const scaleX = image.naturalWidth / image.width;
  const scaleY = image.naturalHeight / image.height;

  const canvas = document.createElement("canvas");
  canvas.width = crop.width * scaleX;
  canvas.height = crop.height * scaleY;
  const ctx = canvas.getContext("2d");
  ctx?.drawImage(
    image,
    crop.x * scaleX,
    crop.y * scaleY,
    crop.width * scaleX,
    crop.height * scaleY,
    0,
    0,
    canvas.width,
    canvas.height
  );
  return canvas.toDataURL("image/png");
}

interface BatchedScreenshot {
  id: string;
  dataUrl: string;
  fileName: string;
}

interface TempPatient {
  id: number;
  firstName: string | null;
  lastName: string | null;
}

const PENDING_SCREENSHOTS_KEY = "copy_agent_pending_screenshots";

export default function AiCopyAgentPage() {
  const { toast } = useToast();
  const [selectedPatient, setSelectedPatient] = useState<Patient | null>(null);
  const [screenshot, setScreenshot] = useState<string | null>(null);
  const [fileName, setFileName] = useState("");
  const [crop, setCrop] = useState<Crop>();
  const [completedCrop, setCompletedCrop] = useState<PixelCrop>();
  const [isCapturing, setIsCapturing] = useState(false);
  const [countdown, setCountdown] = useState<number | null>(null);
  const [isSaving, setIsSaving] = useState(false);
  const [isDetecting, setIsDetecting] = useState(false);
  const [batch, setBatch] = useState<BatchedScreenshot[]>([]);
  const streamRef = useRef<MediaStream | null>(null);
  const imgRef = useRef<HTMLImageElement | null>(null);

  const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
    imgRef.current = e.currentTarget;
    const { width, height } = e.currentTarget;
    const fullCrop = centerCrop(
      makeAspectCrop({ unit: "%", width: 100 }, width / height, width, height),
      width,
      height
    );
    setCrop(fullCrop);
    setCompletedCrop({
      unit: "px",
      x: 0,
      y: 0,
      width,
      height,
    });
  };

  const stopStream = () => {
    streamRef.current?.getTracks().forEach((track) => track.stop());
    streamRef.current = null;
  };

  const handleCapture = async () => {
    setIsCapturing(true);
    try {
      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: { displaySurface: "monitor" },
      });
      streamRef.current = stream;

      const video = document.createElement("video");
      video.srcObject = stream;
      video.muted = true;
      await video.play();
      await new Promise<void>((resolve) => {
        if (video.readyState >= 2) resolve();
        else video.onloadeddata = () => resolve();
      });

      for (let secondsLeft = 3; secondsLeft > 0; secondsLeft--) {
        setCountdown(secondsLeft);
        await new Promise((resolve) => setTimeout(resolve, 1000));
      }
      setCountdown(null);

      const canvas = document.createElement("canvas");
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      const ctx = canvas.getContext("2d");
      ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);

      stopStream();
      setScreenshot(canvas.toDataURL("image/png"));
      setFileName(`screenshot_${Date.now()}`);
    } catch (error) {
      console.error("Error capturing screenshot:", error);
      const name = error instanceof Error ? error.name : "";
      const description =
        name === "NotAllowedError"
          ? "Screen share permission was denied or the picker was cancelled."
          : name === "NotFoundError"
          ? "No screen/window source was available to capture."
          : !navigator.mediaDevices?.getDisplayMedia
          ? "Screen capture isn't supported in this browser."
          : (error instanceof Error ? error.message : "Screen capture failed.");
      toast({
        title: "Screenshot failed",
        description,
        variant: "destructive",
      });
      stopStream();
    } finally {
      setIsCapturing(false);
      setCountdown(null);
    }
  };

  const handleRetake = () => {
    setScreenshot(null);
    setFileName("");
    setCrop(undefined);
    setCompletedCrop(undefined);
    handleCapture();
  };

  const clearActive = () => {
    setScreenshot(null);
    setFileName("");
    setCrop(undefined);
    setCompletedCrop(undefined);
  };

  // Applies the current crop to the active screenshot and returns it, without touching state.
  const finalizeActive = (): BatchedScreenshot | null => {
    if (!screenshot) return null;
    const croppedImage =
      completedCrop && imgRef.current
        ? getCroppedDataUrl(imgRef.current, completedCrop)
        : screenshot;
    const safeName =
      fileName.trim().replace(/[/\\?%*:|"<>]/g, "-") || `screenshot_${Date.now()}`;
    return { id: crypto.randomUUID(), dataUrl: croppedImage, fileName: safeName };
  };

  const handleAddAnother = async () => {
    const item = finalizeActive();
    if (!item) return;
    setBatch((prev) => [...prev, item]);
    clearActive();
    await handleCapture();
  };

  const handleRemoveBatchItem = (id: string) => {
    setBatch((prev) => prev.filter((item) => item.id !== id));
  };

  const getPatientName = (patient: Patient) =>
    patient.firstName && patient.lastName
      ? `${patient.firstName} ${patient.lastName}`
      : patient.firstName ?? `patient-${patient.id}`;

  const itemsToFiles = async (items: BatchedScreenshot[]): Promise<File[]> => {
    const files: File[] = [];
    for (const item of items) {
      const response = await fetch(item.dataUrl);
      const blob = await response.blob();
      files.push(new File([blob], `${item.fileName}.png`, { type: "image/png" }));
    }
    return files;
  };

  const uploadToPatient = async (
    patientId: number | undefined,
    patientName: string,
    files: File[],
    pending: boolean
  ) => {
    const formData = new FormData();
    formData.append("patientId", String(patientId));
    formData.append("patientName", patientName);
    if (pending) formData.append("pending", "true");
    // Lets the backend keep a local-disk-only debug copy — not shown anywhere in the UI.
    formData.append("screenshotBackup", "true");
    for (const file of files) formData.append("files", file);
    await apiRequest("POST", "/api/claims/upload-to-cloud", formData);
  };

  const getPendingItems = (): BatchedScreenshot[] => {
    const items = [...batch];
    const active = finalizeActive();
    if (active) items.push(active);
    return items;
  };

  const handleSave = async () => {
    if (!selectedPatient) return;
    const items = getPendingItems();
    if (!items.length) return;

    setIsSaving(true);
    try {
      const patientName = getPatientName(selectedPatient);
      const files = await itemsToFiles(items);
      await uploadToPatient(selectedPatient.id, patientName, files, false);

      toast({
        title: "Saved",
        description: `${items.length} screenshot${items.length > 1 ? "s" : ""} saved to ${patientName}'s attachments.`,
      });
      setBatch([]);
      clearActive();
    } catch (error) {
      console.error("Error saving screenshot:", error);
      toast({
        title: "Error",
        description: "Failed to save screenshots to patient attachments.",
        variant: "destructive",
      });
    } finally {
      setIsSaving(false);
    }
  };

  const detectFromFiles = async (files: File[]) => {
    const detectFormData = new FormData();
    for (const file of files) detectFormData.append("files", file);
    const response = await apiRequest("POST", "/api/ai/detect-eligibility-info", detectFormData);
    return response.json();
  };

  const handleAiDetectAndCheck = async () => {
    const items = getPendingItems();
    if (!items.length) return;
    if (selectedPatient) {
      await runAiDetectForSelectedPatient(selectedPatient, items);
    } else {
      await runAiDetectWithoutPatient(items);
    }
  };

  const runAiDetectForSelectedPatient = async (patient: Patient, items: BatchedScreenshot[]) => {
    setIsDetecting(true);
    try {
      const patientName = getPatientName(patient);
      const files = await itemsToFiles(items);

      const [uploadResult, detectResult] = await Promise.allSettled([
        uploadToPatient(patient.id, patientName, files, true),
        detectFromFiles(files),
      ]);

      const saved = uploadResult.status === "fulfilled";
      if (saved) {
        setBatch([]);
        clearActive();
      }

      if (detectResult.status === "rejected" || detectResult.value?.error) {
        toast({
          title: saved ? "Saved, but AI detection failed" : "Error",
          description: saved
            ? "Screenshots saved. Enter the Member ID/DOB manually in the chatbot to check eligibility."
            : "Failed to save screenshots and detect Member ID/DOB.",
          variant: saved ? undefined : "destructive",
        });
        return;
      }

      if (!saved) {
        toast({
          title: "Detected, but save failed",
          description: "Read the Member ID/DOB, but failed to save the screenshots. Try Save All again.",
          variant: "destructive",
        });
      }

      const memberId: string | null = detectResult.value?.data?.memberId ?? null;
      const dob: string | null = detectResult.value?.data?.dob ?? null;

      window.dispatchEvent(
        new CustomEvent("chatbot:open-eligibility-id-ready", {
          detail: {
            memberId,
            dob,
            autoCheck: "mh",
            patient: {
              id: patient.id,
              firstName: patient.firstName,
              lastName: patient.lastName,
              insuranceId: patient.insuranceId ?? null,
              insuranceProvider: null,
              dateOfBirth: patient.dateOfBirth ?? null,
            },
            patientId: patient.id,
            pendingFolderPatientName: patientName,
          },
        })
      );
    } finally {
      setIsDetecting(false);
    }
  };

  // No patient selected: detect first (need memberId+dob to create a patient at all), then
  // either auto-create a temp "PID-<id>" patient and save under it, or — if detection came back
  // incomplete — leave the screenshots unsaved and let the user complete the details in the
  // chatbot manually; insurance-status-page.tsx picks the pending screenshots back up once that
  // manual check resolves to a real patient.
  const runAiDetectWithoutPatient = async (items: BatchedScreenshot[]) => {
    setIsDetecting(true);
    try {
      const files = await itemsToFiles(items);

      let detected: { memberId: string | null; dob: string | null };
      try {
        const json = await detectFromFiles(files);
        if (json?.error) throw new Error(json.message || "Detection failed");
        detected = { memberId: json?.data?.memberId ?? null, dob: json?.data?.dob ?? null };
      } catch (error) {
        console.error("Error detecting Member ID/DOB:", error);
        toast({
          title: "Error",
          description: "Failed to read the screenshots. Please try again.",
          variant: "destructive",
        });
        return;
      }

      const { memberId, dob } = detected;

      if (memberId && dob) {
        let tempPatient: TempPatient;
        try {
          const res = await apiRequest("POST", "/api/patients/create-temp", { memberId, dob });
          const json = await res.json();
          tempPatient = json.data;
        } catch (error) {
          console.error("Error creating temp patient:", error);
          toast({
            title: "Error",
            description: "Failed to create a patient record for this screenshot.",
            variant: "destructive",
          });
          return;
        }

        const patientName = getPatientName(tempPatient as Patient);
        try {
          await uploadToPatient(tempPatient.id, patientName, files, false);
        } catch (error) {
          console.error("Error saving screenshots to temp patient:", error);
          toast({
            title: "Detected, but save failed",
            description: `Created ${patientName}, but failed to save the screenshots. Select them from the patient list and try Save All.`,
            variant: "destructive",
          });
          return;
        }

        setBatch([]);
        clearActive();
        setSelectedPatient(tempPatient as Patient);
        toast({
          title: "Patient created",
          description: `Saved as ${patientName}. Its name will update automatically once the eligibility check confirms it.`,
        });

        window.dispatchEvent(
          new CustomEvent("chatbot:open-eligibility-id-ready", {
            detail: {
              memberId,
              dob,
              autoCheck: "mh",
              patient: {
                id: tempPatient.id,
                firstName: tempPatient.firstName,
                lastName: tempPatient.lastName,
                insuranceId: memberId,
                insuranceProvider: null,
                dateOfBirth: dob,
              },
              patientId: tempPatient.id,
            },
          })
        );
      } else {
        try {
          sessionStorage.setItem(
            PENDING_SCREENSHOTS_KEY,
            JSON.stringify(items.map((item) => ({ dataUrl: item.dataUrl, fileName: item.fileName })))
          );
        } catch {}

        toast({
          title: "Couldn't read Member ID/DOB",
          description:
            "Complete the details in the chatbot — your screenshots will attach automatically once that check finishes.",
        });

        window.dispatchEvent(
          new CustomEvent("chatbot:open-eligibility-id-ready", {
            detail: { memberId, dob, autoCheck: "mh", patient: null },
          })
        );
      }
    } finally {
      setIsDetecting(false);
    }
  };

  return (
    <div className="container mx-auto space-y-6">

      {/* Hero */}
      <div className="text-center space-y-3">
        <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-violet-100 mb-2">
          <Copy className="h-8 w-8 text-violet-600" />
        </div>
        <h1 className="text-3xl font-bold tracking-tight">Copy Agent</h1>
        <p className="text-muted-foreground text-base max-w-xl mx-auto">
          An AI agent reads and copies data including images and brings them to this app
          automatically. No manual input required.
        </p>
      </div>

      {/* Screenshot capture */}
      <Card>
        <CardHeader>
          <CardTitle>Capture Screenshot</CardTitle>
          <CardDescription>
            Capture your screen and save it to a patient's attachments. Take multiple
            screenshots and save them together as one batch.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          {batch.length > 0 && (
            <div className="flex flex-wrap gap-2">
              {batch.map((item) => (
                <div key={item.id} className="relative">
                  <img
                    src={item.dataUrl}
                    alt={item.fileName}
                    className="h-16 w-16 rounded-md border object-cover"
                  />
                  <button
                    type="button"
                    onClick={() => handleRemoveBatchItem(item.id)}
                    disabled={isSaving}
                    className="absolute -top-1.5 -right-1.5 rounded-full bg-background border shadow-sm p-0.5"
                    title="Remove from batch"
                  >
                    <X className="h-3 w-3" />
                  </button>
                </div>
              ))}
            </div>
          )}

          {screenshot ? (
            <div className="space-y-4">
              <ReactCrop
                crop={crop}
                onChange={(_, percentCrop) => setCrop(percentCrop)}
                onComplete={(pixelCrop) => setCompletedCrop(pixelCrop)}
              >
                <img
                  src={screenshot}
                  alt="Captured screenshot"
                  onLoad={handleImageLoad}
                  className="w-full rounded-lg border object-contain max-h-96"
                />
              </ReactCrop>
              <p className="text-xs text-muted-foreground">
                Drag the corners to crop, or leave as-is to save the full screenshot.
              </p>
              <div className="space-y-1.5 max-w-sm">
                <Label htmlFor="screenshot-filename">File name</Label>
                <div className="flex items-center gap-1">
                  <Input
                    id="screenshot-filename"
                    value={fileName}
                    onChange={(e) => setFileName(e.target.value)}
                    placeholder="screenshot"
                  />
                  <span className="text-sm text-muted-foreground">.png</span>
                </div>
              </div>
              <div className="flex flex-wrap gap-3">
                <Button variant="outline" onClick={handleRetake} disabled={isCapturing || isSaving}>
                  <RotateCcw className="h-4 w-4 mr-2" />
                  Retake
                </Button>
                <Button variant="outline" onClick={handleAddAnother} disabled={isCapturing || isSaving}>
                  <Plus className="h-4 w-4 mr-2" />
                  Add Another
                </Button>
                <Button
                  onClick={handleSave}
                  disabled={!selectedPatient || isSaving || isDetecting}
                  title={!selectedPatient ? "Select a patient below first" : undefined}
                >
                  <Save className="h-4 w-4 mr-2" />
                  {isSaving ? "Saving..." : `Save All${batch.length ? ` (${batch.length + 1})` : ""}`}
                </Button>
                <Button
                  variant="secondary"
                  onClick={handleAiDetectAndCheck}
                  disabled={isSaving || isDetecting}
                >
                  <Sparkles className="h-4 w-4 mr-2" />
                  {isDetecting ? "Detecting..." : "AI Detect & Check Eligibility"}
                </Button>
              </div>
              {!selectedPatient && (
                <p className="text-xs text-muted-foreground">
                  Select a patient below to enable Save All, or use "AI Detect &amp; Check
                  Eligibility" without selecting one to create a patient automatically.
                </p>
              )}
            </div>
          ) : (
            <div className="flex flex-wrap gap-3">
              <Button onClick={handleCapture} disabled={isCapturing}>
                <Camera className="h-4 w-4 mr-2" />
                {countdown !== null
                  ? `Capturing in ${countdown}...`
                  : isCapturing
                  ? "Waiting for screen share..."
                  : batch.length > 0
                  ? "Take Another Screenshot"
                  : "Take Screenshot"}
              </Button>
              {batch.length > 0 && (
                <>
                  <Button
                    onClick={handleSave}
                    disabled={!selectedPatient || isSaving || isDetecting}
                    title={!selectedPatient ? "Select a patient below first" : undefined}
                  >
                    <Save className="h-4 w-4 mr-2" />
                    {isSaving ? "Saving..." : `Save All (${batch.length})`}
                  </Button>
                  <Button
                    variant="secondary"
                    onClick={handleAiDetectAndCheck}
                    disabled={isSaving || isDetecting}
                  >
                    <Sparkles className="h-4 w-4 mr-2" />
                    {isDetecting ? "Detecting..." : "AI Detect & Check Eligibility"}
                  </Button>
                </>
              )}
            </div>
          )}
        </CardContent>
      </Card>

      {/* Patient search */}
      <Card>
        <CardHeader>
          <CardTitle>Patient Records</CardTitle>
          <CardDescription>
            Select the patient this screenshot belongs to, or leave unselected and use
            "AI Detect &amp; Check Eligibility" to create one automatically.
          </CardDescription>
        </CardHeader>
        <CardContent>
          <PatientTable
            allowCheckbox={true}
            onSelectPatient={setSelectedPatient}
          />
        </CardContent>
      </Card>

    </div>
  );
}
