"use client";

import { useState, useRef } from "react";
import NextImage from "next/image";
import { trpc } from "~/lib/trpc/client.js";

interface CoverArtSectionProps {
  projectId: string;
  coverImageUrl?: string | null;
  coverFocusY?: number;
  projectColor?: string | null;
  projectName: string;
  canEdit: boolean;
}

export function CoverArtSection({ projectId, coverImageUrl, coverFocusY = 50, projectColor, projectName, canEdit }: CoverArtSectionProps) {
  const [imageUrl, setImageUrl] = useState(coverImageUrl ?? null);
  const [focusY, setFocusY] = useState(coverFocusY);
  const [generating, setGenerating] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [customPrompt, setCustomPrompt] = useState("");
  const [showPromptInput, setShowPromptInput] = useState(false);
  const [showFocusSlider, setShowFocusSlider] = useState(false);
  const [isAiGenerated, setIsAiGenerated] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const utils = trpc.useUtils();

  const { data: imageGenStatus } = trpc.project.isImageGenConfigured.useQuery();
  const generateMutation = trpc.project.generateCover.useMutation();
  const uploadMutation = trpc.project.uploadCover.useMutation();
  const removeMutation = trpc.project.removeCover.useMutation();
  const focusMutation = trpc.project.updateCoverFocus.useMutation();

  const handleGenerate = async () => {
    setError(null);
    setGenerating(true);
    try {
      const result = await generateMutation.mutateAsync({
        projectId,
        ...(customPrompt.trim() ? { prompt: customPrompt.trim() } : {}),
      });
      setImageUrl(result.coverImageUrl);
      setIsAiGenerated(true);
      setShowPromptInput(false);
      setCustomPrompt("");
      void utils.project.getById.invalidate({ id: projectId });
      void utils.project.listWithCosts.invalidate();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to generate cover");
    } finally {
      setGenerating(false);
    }
  };

  /** Compress an image file to WebP/JPEG via canvas, targeting max 1920px and ~200-400KB output */
  const compressImage = (file: File, maxDim = 1920, quality = 0.82): Promise<string> =>
    new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => {
        let { width, height } = img;
        if (width > maxDim || height > maxDim) {
          const scale = maxDim / Math.max(width, height);
          width = Math.round(width * scale);
          height = Math.round(height * scale);
        }
        const canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        const ctx2d = canvas.getContext("2d");
        if (!ctx2d) { reject(new Error("Canvas not supported")); return; }
        ctx2d.drawImage(img, 0, 0, width, height);
        // Prefer WebP, fall back to JPEG
        let dataUrl = canvas.toDataURL("image/webp", quality);
        if (!dataUrl.startsWith("data:image/webp")) {
          dataUrl = canvas.toDataURL("image/jpeg", quality);
        }
        resolve(dataUrl);
      };
      img.onerror = () => reject(new Error("Failed to load image"));
      img.src = URL.createObjectURL(file);
    });

  const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    if (!file.type.startsWith("image/")) {
      setError("Please select an image file (PNG, JPG, WebP, etc.)");
      return;
    }

    if (file.size > 10 * 1024 * 1024) {
      setError("Image too large. Maximum upload size is 10 MB.");
      return;
    }

    setError(null);
    setUploading(true);

    try {
      const dataUrl = await compressImage(file);

      const result = await uploadMutation.mutateAsync({
        projectId,
        imageDataUrl: dataUrl,
      });
      setImageUrl(result.coverImageUrl);
      void utils.project.getById.invalidate({ id: projectId });
      void utils.project.listWithCosts.invalidate();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to upload image");
    } finally {
      setUploading(false);
      if (fileInputRef.current) fileInputRef.current.value = "";
    }
  };

  const handleRemove = async () => {
    setError(null);
    try {
      await removeMutation.mutateAsync({ projectId });
      setImageUrl(null);
      setShowFocusSlider(false);
      void utils.project.getById.invalidate({ id: projectId });
      void utils.project.listWithCosts.invalidate();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to remove cover");
    }
  };

  const handleFocusSave = async () => {
    try {
      await focusMutation.mutateAsync({ projectId, coverFocusY: focusY });
      setShowFocusSlider(false);
      void utils.project.getById.invalidate({ id: projectId });
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to save focus point");
    }
  };

  const initials = projectName
    .split(/\s+/)
    .map((w) => w[0])
    .filter(Boolean)
    .slice(0, 2)
    .join("")
    .toUpperCase();

  return (
    <div className="relative overflow-hidden rounded-xl border border-gray-200 dark:border-gray-700">
      {/* Cover image or placeholder */}
      {imageUrl ? (
        <div className="relative">
          <NextImage
            src={imageUrl}
            alt={`Cover art for ${projectName}`}
            width={1024}
            height={1024}
            className="w-full object-cover"
            style={{
              height: "clamp(16rem, 22vw, 22rem)",
              objectPosition: `center ${focusY}%`,
            }}
            unoptimized={imageUrl.startsWith("data:")}
            priority
          />
          {/* Gradient overlay at bottom for readability */}
          <div className="absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-black/40 to-transparent" />
          {/* AI Generated badge (EGAI 4.3.1.3) */}
          {isAiGenerated && (
            <span className="absolute left-3 top-3 inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300 shadow-sm">
              <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
              </svg>
              AI Generated
            </span>
          )}
        </div>
      ) : (
        <div
          className="flex flex-col items-center justify-center gap-1"
          style={{
            height: "clamp(10rem, 16vw, 14rem)",
            background: projectColor
              ? `linear-gradient(135deg, ${projectColor}22, ${projectColor}44)`
              : "linear-gradient(135deg, #e0e7ff, #c7d2fe)",
          }}
        >
          <span
            className="text-4xl font-bold opacity-30"
            style={{ color: projectColor ?? "#6366f1" }}
          >
            {initials}
          </span>
          <span className="text-[10px] font-medium tracking-wide text-gray-400 dark:text-gray-500">
            1024 × 1024 px
          </span>
        </div>
      )}

      {/* Controls overlay */}
      {canEdit && (
        <div className="absolute right-3 top-3 flex items-center gap-2">
          {/* Focus point adjuster — only when image exists */}
          {imageUrl && (
            <button
              type="button"
              onClick={() => setShowFocusSlider((v) => !v)}
              className="inline-flex items-center gap-1.5 rounded-lg bg-white/90 px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm backdrop-blur transition hover:bg-white dark:bg-gray-800/90 dark:text-gray-200 dark:hover:bg-gray-800"
              title="Adjust vertical focus point"
            >
              <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" />
              </svg>
              Focus
            </button>
          )}

          {/* Generate with AI */}
          {imageGenStatus?.configured && (
            <button
              type="button"
              onClick={() => {
                if (showPromptInput) {
                  handleGenerate();
                } else {
                  setShowPromptInput(true);
                }
              }}
              disabled={generating}
              className="inline-flex items-center gap-1.5 rounded-lg bg-white/90 px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm backdrop-blur transition hover:bg-white disabled:opacity-50 dark:bg-gray-800/90 dark:text-gray-200 dark:hover:bg-gray-800"
              title="Generate cover art with AI"
            >
              {generating ? (
                <>
                  <svg className="h-3.5 w-3.5 animate-spin" fill="none" viewBox="0 0 24 24">
                    <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                    <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                  </svg>
                  Generating...
                </>
              ) : (
                <>
                  <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
                  </svg>
                  {showPromptInput ? "Generate" : "AI Cover"}
                </>
              )}
            </button>
          )}

          {/* Upload */}
          <button
            type="button"
            onClick={() => fileInputRef.current?.click()}
            disabled={uploading}
            className="inline-flex items-center gap-1.5 rounded-lg bg-white/90 px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm backdrop-blur transition hover:bg-white disabled:opacity-50 dark:bg-gray-800/90 dark:text-gray-200 dark:hover:bg-gray-800"
          >
            {uploading ? (
              <>
                <svg className="h-3.5 w-3.5 animate-spin" fill="none" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                </svg>
                Uploading...
              </>
            ) : (
              <>
                <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
                </svg>
                Upload
              </>
            )}
          </button>

          <input
            ref={fileInputRef}
            type="file"
            accept="image/png,image/jpeg,image/webp,image/tiff,image/bmp"
            className="hidden"
            onChange={handleFileSelect}
          />

          {/* Remove */}
          {imageUrl && (
            <button
              type="button"
              onClick={handleRemove}
              disabled={removeMutation.isPending}
              className="inline-flex items-center gap-1.5 rounded-lg bg-red-500/80 px-3 py-1.5 text-xs font-medium text-white shadow-sm backdrop-blur transition hover:bg-red-600 disabled:opacity-50"
              title="Remove cover art"
            >
              <svg className="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
              </svg>
            </button>
          )}
        </div>
      )}

      {/* Focus point slider */}
      {showFocusSlider && imageUrl && canEdit && (
        <div className="absolute inset-x-0 bottom-0 bg-white/95 px-4 py-3 backdrop-blur dark:bg-gray-900/95">
          <div className="flex items-center gap-3">
            <label className="text-xs font-medium text-gray-600 dark:text-gray-300 whitespace-nowrap">
              Focus point
            </label>
            <span className="text-[10px] text-gray-400">Top</span>
            <input
              type="range"
              min={0}
              max={100}
              value={focusY}
              onChange={(e) => setFocusY(Number(e.target.value))}
              className="flex-1 accent-brand-600"
            />
            <span className="text-[10px] text-gray-400">Bottom</span>
            <span className="w-8 text-center text-xs tabular-nums text-gray-500">{focusY}%</span>
            <button
              type="button"
              onClick={handleFocusSave}
              disabled={focusMutation.isPending}
              className="rounded-lg bg-brand-600 px-3 py-1 text-xs font-medium text-white hover:bg-brand-700 disabled:opacity-50"
            >
              {focusMutation.isPending ? "..." : "Save"}
            </button>
            <button
              type="button"
              onClick={() => {
                setFocusY(coverFocusY);
                setShowFocusSlider(false);
              }}
              className="text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400"
            >
              Cancel
            </button>
          </div>
        </div>
      )}

      {/* Custom prompt input (shown when AI Cover is clicked) */}
      {showPromptInput && !showFocusSlider && canEdit && (
        <div className="absolute inset-x-0 bottom-0 bg-white/95 p-3 backdrop-blur dark:bg-gray-900/95">
          <div className="flex items-center gap-2">
            <input
              type="text"
              value={customPrompt}
              onChange={(e) => setCustomPrompt(e.target.value)}
              placeholder="Optional: describe the style you want..."
              className="flex-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200"
              onKeyDown={(e) => {
                if (e.key === "Enter") handleGenerate();
                if (e.key === "Escape") {
                  setShowPromptInput(false);
                  setCustomPrompt("");
                }
              }}
              autoFocus
            />
            <button
              type="button"
              onClick={handleGenerate}
              disabled={generating}
              className="rounded-lg bg-brand-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-brand-700 disabled:opacity-50"
            >
              {generating ? "..." : "Generate"}
            </button>
            <button
              type="button"
              onClick={() => {
                setShowPromptInput(false);
                setCustomPrompt("");
              }}
              className="rounded-lg px-2 py-1.5 text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400"
            >
              Cancel
            </button>
          </div>
        </div>
      )}

      {/* Error message */}
      {error && (
        <div className="absolute inset-x-0 bottom-0 bg-red-50/95 px-3 py-2 text-xs text-red-700 backdrop-blur dark:bg-red-950/90 dark:text-red-300">
          {error}
          <button
            type="button"
            onClick={() => setError(null)}
            className="ml-2 font-medium underline"
          >
            Dismiss
          </button>
        </div>
      )}
    </div>
  );
}
