import { useEffect, useMemo, useState } from "react";
import type { Project, Scene } from "../api/client";
import { generateSceneImage } from "../api/client";
import { formatAiEditCreditsDisplay } from "../lib/formatAiEditCredits";

// AI image generation costs this many AI-edit credits per image (all plans).
// Kept in sync with the backend GENERATE_IMAGE_CREDIT_COST.
export const AI_IMAGE_CREDIT_COST = 3;

export interface GenerateSceneImageModalProps {
  open: boolean;
  onClose: () => void;
  scene: Scene;
  project: Project;
  /**
   * Whether the owner has enough AI-edit budget for one generation (monthly
   * allowance + purchased pool).
   */
  canGenerate: boolean;
  /** Credits one generation costs (shown in the modal for every plan). */
  creditCost: number;
  /**
   * True when the viewer is a collaborator on a shared project (spending the OWNER's
   * credit pool). They can't fix an exhausted pool by upgrading their own plan.
   */
  isCollaborator?: boolean;
  /** Total AI-edit budget available (allowance + purchased pool). */
  creditsRemaining: number;
  /** True when the blocker is the OWNER's exhausted access, not the viewer's own. */
  ownerBlocked?: boolean;
  onUpgrade: () => void;
  /** Navigate to the billing page from the inline "Upgrade now" link. */
  onUpgradeNow: () => void;
  /** Shown instead of the self-upgrade prompt when `ownerBlocked`. */
  onOwnerBlocked?: () => void;
  onImageReady: (imageBase64: string, refinedPrompt: string) => void;
  onGenerateStart?: () => void;
  onGenerateError?: (message: string) => void;
}

export default function GenerateSceneImageModal({
  open,
  onClose,
  scene,
  project,
  canGenerate,
  creditCost,
  isCollaborator = false,
  creditsRemaining,
  ownerBlocked,
  onUpgrade,
  onUpgradeNow,
  onOwnerBlocked,
  onImageReady,
  onGenerateStart,
  onGenerateError,
}: GenerateSceneImageModalProps) {
  const [imageDescription, setImageDescription] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [generating, setGenerating] = useState(false);

  const placeholderHint = useMemo(() => {
    const v = (scene.visual_description || "").trim();
    if (!v) return "Describe the image you want (subject, style, mood, colors)…";
    const first = v.split("\n").find((line) => line.trim())?.trim() ?? v;
    return first.length > 120 ? `${first.slice(0, 120)}…` : first;
  }, [scene.visual_description]);

  useEffect(() => {
    if (!open) return;
    setImageDescription("");
    setError(null);
    setGenerating(false);
  }, [open, scene.id]);

  if (!open) return null;

  // A collaborator blocked by the owner's free plan can't act on an upgrade prompt.
  const promptForAccess = () => {
    if (ownerBlocked) onOwnerBlocked?.();
    else onUpgrade();
  };

  const handleGenerate = async () => {
    const desc = imageDescription.trim();
    if (desc.length < 3) {
      setError("Image description must be at least 3 characters.");
      return;
    }
    if (!canGenerate) {
      promptForAccess();
      return;
    }

    // Keep the modal open and show a generating state so the user sees progress and
    // any error, instead of the modal vanishing with no feedback.
    setError(null);
    setGenerating(true);
    onGenerateStart?.();

    try {
      const res = await generateSceneImage(project.id, scene.id, {
        image_description: desc,
      });
      // Hand the result to the parent (which shows the keep/discard preview) and close.
      onImageReady(res.data.image_base64, res.data.refined_prompt);
      onClose();
    } catch (err: unknown) {
      const status =
        err && typeof err === "object" && "response" in err
          ? (err as { response?: { status?: number } }).response?.status
          : 0;
      if (status === 403) {
        promptForAccess();
        return;
      }
      const msg =
        err && typeof err === "object" && "response" in err
          ? (err as { response?: { data?: { detail?: string } } }).response?.data
              ?.detail
          : "Image generation failed";
      setError(String(msg || "Image generation failed"));
      onGenerateError?.(String(msg || "Image generation failed"));
    } finally {
      setGenerating(false);
    }
  };

  return (
    <div className="fixed inset-0 z-[105] flex items-center justify-center p-4">
      <div
        className="absolute inset-0 bg-black/50 backdrop-blur-sm"
        onClick={() => { if (!generating) onClose(); }}
        aria-hidden
      />
      <div
        className="relative bg-white rounded-2xl shadow-2xl max-w-lg w-full max-h-[90vh] flex flex-col overflow-hidden"
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-labelledby="generate-scene-image-title"
      >
        <div className="p-4 border-b border-gray-200 flex-shrink-0">
          <h3 id="generate-scene-image-title" className="text-lg font-semibold text-gray-900">
            Generate image with AI
          </h3>
          <p className="text-xs text-gray-500 mt-1">
            Describe the image you want. Your description is the main input.
          </p>
          <p className="text-xs text-gray-400 mt-1">
            Costs{" "}
            <span className="font-medium text-gray-600">
              {creditCost} AI edit credits
            </span>
            {isCollaborator ? (
              <>
                {" "}
                from the project owner&apos;s balance (
                {formatAiEditCreditsDisplay(creditsRemaining)} remaining).
              </>
            ) : (
              <>
                {" "}
                · {formatAiEditCreditsDisplay(creditsRemaining)} remaining
                {!canGenerate && (
                  <>
                    {" "}
                    ·{" "}
                    <button
                      type="button"
                      onClick={onUpgradeNow}
                      className="text-purple-600 hover:text-purple-700 underline font-medium"
                    >
                      Upgrade for more
                    </button>
                  </>
                )}
              </>
            )}
          </p>
        </div>

        {generating ? (
          <div className="flex-1 flex flex-col items-center justify-center gap-4 p-10 text-center min-h-0">
            <div className="w-12 h-12 border-2 border-purple-200 border-t-purple-600 rounded-full animate-spin" />
            <div>
              <p className="text-sm font-medium text-gray-800">Generating image…</p>
              <p className="mt-1 text-xs text-gray-500">
                This can take up to a minute. Please keep this open.
              </p>
            </div>
          </div>
        ) : (
        <div className="flex-1 overflow-y-auto p-4 space-y-4 min-h-0">
          <div>
            <label
              htmlFor="scene-image-description"
              className="block text-[11px] font-medium text-gray-500 uppercase tracking-wider mb-1.5"
            >
              Image description <span className="text-red-500">*</span>
            </label>
            <textarea
              id="scene-image-description"
              value={imageDescription}
              onChange={(e) => setImageDescription(e.target.value)}
              placeholder={placeholderHint}
              rows={4}
              autoFocus
              className="w-full px-3 py-2 text-sm text-gray-800 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 resize-y leading-relaxed"
            />
            <p className="text-xs text-gray-500 mt-2">
              The scene description will also be incorporated into your prompt to generate the
              image.
            </p>
          </div>

          {error ? (
            <p className="text-xs text-red-600" role="alert">
              {error}
            </p>
          ) : null}
        </div>
        )}

        {!generating && (
          <div className="p-4 border-t border-gray-200 flex gap-2 flex-shrink-0">
            <button
              type="button"
              onClick={onClose}
              className="flex-1 px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-50"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={handleGenerate}
              disabled={imageDescription.trim().length < 3}
              className="flex-1 px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed"
            >
              Generate
            </button>
          </div>
        )}
      </div>
    </div>
  );
}
