﻿"use client";

import { useRef, useState } from "react";
import { Video, Upload, X, Plus, Pencil, Trash2, Film } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { addFootagePlate, removeFootagePlate, renameFootagePlate } from "@/actions/shots";
import { useToast } from "@/components/ui/use-toast";
import { cn } from "@/lib/utils";

interface Plate {
  id: string;
  label: string;
  fileUrl: string;
  fileKey: string;
  fileName: string;
  fileSize: bigint | string | null;
  sortOrder: number;
  createdAt: Date;
}

interface FootageViewerProps {
  shot: {
    id: string;
    shotCode: string;
    footagePlates: Plate[];
  };
  canManage: boolean;
  onSaved?: () => void;
}

function uploadViaXhr(
  file: File,
  onProgress: (fraction: number) => void
): Promise<{ url: string; key: string }> {
  return new Promise((resolve, reject) => {
    (async () => {
      // Ask the server for a presigned Hetzner PUT URL, then upload the
      // bytes directly from the browser — this bypasses this app's server
      // (and any reverse-proxy / CDN body size limit, e.g. Cloudflare's
      // 100MB edge cap) entirely for large footage plates.
      let presignedUrl: string;
      let key: string;
      let url: string;
      try {
        const presignRes = await fetch("/api/upload/presign", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ fileName: file.name, contentType: file.type, folder: "videos" }),
        });
        if (!presignRes.ok) {
          const json = await presignRes.json().catch(() => null);
          throw new Error(json?.error ?? `Failed to prepare upload (HTTP ${presignRes.status})`);
        }
        const presignJson = await presignRes.json();
        presignedUrl = presignJson.presignedUrl;
        key = presignJson.key;
        url = presignJson.url;
      } catch (err) {
        reject(err instanceof Error ? err : new Error("Failed to prepare upload"));
        return;
      }

      const xhr = new XMLHttpRequest();
      xhr.open("PUT", presignedUrl);
      xhr.setRequestHeader("Content-Type", file.type);

      xhr.upload.addEventListener("progress", (e) => {
        if (e.lengthComputable) onProgress(e.loaded / e.total);
      });

      xhr.addEventListener("load", () => {
        if (xhr.status >= 200 && xhr.status < 300) resolve({ url, key });
        else reject(new Error(`Upload failed (HTTP ${xhr.status})`));
      });

      xhr.addEventListener("error", () => reject(new Error("Network error")));
      xhr.addEventListener("abort", () => reject(new Error("Upload aborted")));
      xhr.send(file);
    })();
  });
}

function formatSize(size: bigint | string | null): string {
  if (size == null) return "";
  const n = typeof size === "string" ? parseInt(size, 10) : Number(size);
  if (isNaN(n)) return "";
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;
  return `${(n / 1024 / 1024).toFixed(1)} MB`;
}

export function FootageViewer({ shot, canManage, onSaved }: FootageViewerProps) {
  const { toast } = useToast();
  const fileInputRef = useRef<HTMLInputElement>(null);

  const [plates, setPlates] = useState<Plate[]>(shot.footagePlates ?? []);
  const [selectedId, setSelectedId] = useState<string | null>(
    (shot.footagePlates ?? [])[0]?.id ?? null
  );
  const [pendingFile, setPendingFile] = useState<File | null>(null);
  const [pendingLabel, setPendingLabel] = useState("");
  const [uploading, setUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [editLabel, setEditLabel] = useState("");
  const [deletingId, setDeletingId] = useState<string | null>(null);

  const selectedPlate = plates.find((p) => p.id === selectedId) ?? null;

  // â”€â”€ upload new plate â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setPendingFile(file);
    setPendingLabel("");
    e.target.value = "";
  };

  const handleUpload = async () => {
    if (!pendingFile) return;
    setUploading(true);
    setProgress(0);
    try {
      const { url, key } = await uploadViaXhr(pendingFile, setProgress);
      const result = await addFootagePlate({
        shotId: shot.id,
        fileUrl: url,
        fileKey: key,
        fileName: pendingFile.name,
        fileSize: pendingFile.size,
        label: pendingLabel.trim() || `Plate ${plates.length + 1}`,
      });
      const newPlate = result.plate as Plate;
      const updated = [...plates, newPlate];
      setPlates(updated);
      setSelectedId(newPlate.id);
      setPendingFile(null);
      setPendingLabel("");
      toast({ title: "Footage plate added" });
      onSaved?.();
    } catch (e) {
      toast({
        title: "Upload failed",
        description: e instanceof Error ? e.message : undefined,
        variant: "destructive",
      });
    } finally {
      setUploading(false);
      setProgress(0);
    }
  };

  const handleCancelPending = () => {
    setPendingFile(null);
    setPendingLabel("");
  };

  // â”€â”€ remove plate â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
  const handleRemove = async (plateId: string) => {
    setDeletingId(plateId);
    try {
      await removeFootagePlate(plateId);
      const updated = plates.filter((p) => p.id !== plateId);
      setPlates(updated);
      if (selectedId === plateId) setSelectedId(updated[0]?.id ?? null);
      toast({ title: "Plate removed" });
      onSaved?.();
    } catch (e) {
      toast({
        title: "Failed to remove plate",
        description: e instanceof Error ? e.message : undefined,
        variant: "destructive",
      });
    } finally {
      setDeletingId(null);
    }
  };

  // â”€â”€ rename plate â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
  const startEdit = (plate: Plate) => {
    setEditingId(plate.id);
    setEditLabel(plate.label);
  };

  const commitEdit = async (plateId: string) => {
    try {
      await renameFootagePlate(plateId, editLabel);
      setPlates((prev) =>
        prev.map((p) => (p.id === plateId ? { ...p, label: editLabel.trim() } : p))
      );
      onSaved?.();
    } catch (e) {
      toast({
        title: "Failed to rename plate",
        description: e instanceof Error ? e.message : undefined,
        variant: "destructive",
      });
    } finally {
      setEditingId(null);
    }
  };

  return (
    <div className="space-y-4 max-w-4xl">
      {/* Header */}
      <h3 className="text-sm font-semibold text-zinc-300 flex items-center gap-2">
        <Video className="h-4 w-4 text-amber-500" />
        Footage Plates
        <span className="text-xs font-mono text-zinc-500">{shot.shotCode}</span>
        {plates.length > 0 && (
          <span className="ml-1 text-xs font-mono bg-zinc-800 text-zinc-400 px-1.5 py-0.5 rounded">
            {plates.length}
          </span>
        )}
      </h3>

      {/* Video player */}
      {selectedPlate ? (
        <div className="relative w-full rounded-xl overflow-hidden bg-black border border-zinc-800 aspect-video">
          <video
            key={selectedPlate.fileUrl}
            src={selectedPlate.fileUrl}
            controls
            className="w-full h-full"
            preload="metadata"
          >
            Your browser does not support the video tag.
          </video>
        </div>
      ) : (
        !pendingFile && (
          <div
            className={cn(
              "flex flex-col items-center justify-center py-20 gap-4 rounded-xl border-2 border-dashed border-zinc-800 text-zinc-500",
              canManage && "hover:border-amber-500/40 cursor-pointer transition-colors"
            )}
            onClick={() => canManage && fileInputRef.current?.click()}
          >
            <Film className="h-12 w-12 opacity-30" />
            <p className="text-sm">No footage plates yet.</p>
            {canManage && <p className="text-xs text-zinc-600">Click to add a video file</p>}
          </div>
        )
      )}

      {/* Plate list */}
      {plates.length > 0 && (
        <div className="space-y-1">
          {plates.map((plate, i) => (
            <div
              key={plate.id}
              className={cn(
                "flex items-center gap-2 px-3 py-2 rounded-lg border cursor-pointer transition-colors group",
                plate.id === selectedId
                  ? "border-amber-500/40 bg-amber-500/5"
                  : "border-zinc-800 bg-zinc-900/50 hover:border-zinc-700"
              )}
              onClick={() => {
                if (editingId !== plate.id) setSelectedId(plate.id);
              }}
            >
              {/* Index badge */}
              <span className="shrink-0 w-5 h-5 rounded text-[10px] font-mono font-bold flex items-center justify-center bg-zinc-800 text-zinc-400">
                {i + 1}
              </span>

              {/* Label (edit or display) */}
              {editingId === plate.id ? (
                <Input
                  autoFocus
                  value={editLabel}
                  onChange={(e) => setEditLabel(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === "Enter") commitEdit(plate.id);
                    if (e.key === "Escape") setEditingId(null);
                  }}
                  onBlur={() => commitEdit(plate.id)}
                  className="h-6 text-xs py-0 px-2 flex-1"
                  onClick={(e) => e.stopPropagation()}
                />
              ) : (
                <span className="flex-1 text-sm text-zinc-200 truncate">
                  {plate.label || `Plate ${i + 1}`}
                </span>
              )}

              {/* File info */}
              {plate.fileName && (
                <span className="text-xs text-zinc-500 truncate max-w-[140px] hidden sm:block font-mono">
                  {plate.fileName}
                </span>
              )}
              {plate.fileSize && (
                <span className="text-xs text-zinc-600 shrink-0">{formatSize(plate.fileSize)}</span>
              )}

              {/* Actions */}
              {canManage && editingId !== plate.id && (
                <div
                  className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
                  onClick={(e) => e.stopPropagation()}
                >
                  <button
                    title="Rename plate"
                    onClick={() => startEdit(plate)}
                    className="p-1 rounded text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800 transition-colors"
                  >
                    <Pencil className="h-3.5 w-3.5" />
                  </button>
                  <button
                    title="Remove plate"
                    disabled={deletingId === plate.id}
                    onClick={() => handleRemove(plate.id)}
                    className="p-1 rounded text-zinc-500 hover:text-red-400 hover:bg-zinc-800 transition-colors disabled:opacity-40"
                  >
                    <Trash2 className="h-3.5 w-3.5" />
                  </button>
                </div>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Pending file row */}
      {pendingFile && !uploading && (
        <div className="flex items-center gap-3 p-3 rounded-lg bg-zinc-900 border border-zinc-700">
          <Video className="h-5 w-5 text-zinc-400 shrink-0" />
          <div className="flex-1 min-w-0">
            <p className="text-sm text-zinc-300 truncate">{pendingFile.name}</p>
            <p className="text-xs text-zinc-500">{(pendingFile.size / 1024 / 1024).toFixed(1)} MB</p>
          </div>
          <Input
            placeholder="Label (optional)"
            value={pendingLabel}
            onChange={(e) => setPendingLabel(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && handleUpload()}
            className="w-36 h-7 text-xs py-0"
          />
          <Button size="sm" onClick={handleUpload}>
            <Upload className="h-3.5 w-3.5 mr-1.5" />
            Upload
          </Button>
          <button
            type="button"
            onClick={handleCancelPending}
            className="text-zinc-500 hover:text-zinc-300"
          >
            <X className="h-4 w-4" />
          </button>
        </div>
      )}

      {/* Upload progress */}
      {uploading && (
        <div className="space-y-2 p-3 rounded-lg bg-zinc-900 border border-zinc-800">
          <div className="flex items-center justify-between text-xs text-zinc-400">
            <span>Uploading footageâ€¦</span>
            <span>{Math.round(progress * 100)}%</span>
          </div>
          <div className="h-1.5 bg-zinc-800 rounded-full overflow-hidden">
            <div
              className="h-full bg-amber-500 transition-all duration-200"
              style={{ width: `${progress * 100}%` }}
            />
          </div>
        </div>
      )}

      {/* Add plate button */}
      {canManage && !pendingFile && !uploading && (
        <Button
          variant="outline"
          size="sm"
          className="text-xs"
          onClick={() => fileInputRef.current?.click()}
        >
          <Plus className="h-3.5 w-3.5 mr-1.5" />
          Add Plate
        </Button>
      )}

      <input
        ref={fileInputRef}
        type="file"
        accept="video/mp4,video/quicktime,video/x-msvideo,video/x-matroska,video/webm,video/*"
        className="hidden"
        onChange={handleFileChange}
      />
    </div>
  );
}
