"use client";

import { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Privacy } from "@prisma/client";
import { filenameWithoutExtension } from "@/lib/constants";
import type { ItemMetadata } from "@/lib/types";
import { CategorySelect } from "./CategorySelect";
import { PrivacyToggle } from "./PrivacyToggle";
import { ResolutionSelect } from "./ResolutionSelect";

type AudioItem = {
  id: string;
  file: File;
  path: string | null;
  uploading: boolean;
  metadata: ItemMetadata;
};

function defaultMetadata(title = ""): ItemMetadata {
  return {
    title,
    description: "",
    tags: "",
    privacy: "PUBLIC" as Privacy,
    categoryId: "10",
    resolution: "1280x720",
    notifySubscribers: true,
    madeForKids: false,
    embeddable: true,
    creativeCommons: false,
    includeWatermark: true,
  };
}

export function UploadForm() {
  const router = useRouter();
  const [imageFile, setImageFile] = useState<File | null>(null);
  const [imagePath, setImagePath] = useState<string | null>(null);
  const [imageUploading, setImageUploading] = useState(false);
  const [audioItems, setAudioItems] = useState<AudioItem[]>([]);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [quota, setQuota] = useState<{ remaining: number; limit: number } | null>(null);

  const loadQuota = useCallback(async () => {
    const res = await fetch("/api/quota");
    if (res.ok) {
      const data = await res.json();
      setQuota({ remaining: data.remaining, limit: data.limit });
    }
  }, []);

  useEffect(() => {
    loadQuota();
  }, [loadQuota]);

  async function uploadFile(file: File, type: "image" | "audio"): Promise<string> {
    const formData = new FormData();
    formData.append("file", file);
    formData.append("type", type);
    const res = await fetch("/api/upload", { method: "POST", body: formData });
    if (!res.ok) {
      const data = await res.json();
      throw new Error(data.error || "Upload failed");
    }
    const data = await res.json();
    return data.path;
  }

  async function handleImageChange(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    setError(null);
    setImageFile(file);
    setImageUploading(true);
    try {
      const path = await uploadFile(file, "image");
      setImagePath(path);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Image upload failed");
      setImageFile(null);
      setImagePath(null);
    } finally {
      setImageUploading(false);
    }
  }

  async function handleAudioChange(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;
    setError(null);

    for (const file of files) {
      const id = crypto.randomUUID();
      const autoTitle = filenameWithoutExtension(file.name);

      setAudioItems((prev) => [
        ...prev,
        {
          id,
          file,
          path: null,
          uploading: true,
          metadata: defaultMetadata(autoTitle),
        },
      ]);

      try {
        const path = await uploadFile(file, "audio");
        setAudioItems((prev) =>
          prev.map((item) =>
            item.id === id ? { ...item, path, uploading: false } : item,
          ),
        );
      } catch (err) {
        setError(err instanceof Error ? err.message : "Audio upload failed");
        setAudioItems((prev) => prev.filter((item) => item.id !== id));
      }
    }

    e.target.value = "";
  }

  function updateItemMetadata(id: string, updates: Partial<ItemMetadata>) {
    setAudioItems((prev) =>
      prev.map((item) =>
        item.id === id
          ? { ...item, metadata: { ...item.metadata, ...updates } }
          : item,
      ),
    );
  }

  function removeAudioItem(id: string) {
    setAudioItems((prev) => prev.filter((item) => item.id !== id));
  }

  const readyAudios = audioItems.filter((a) => a.path && !a.uploading);
  const canSubmit =
    imagePath &&
    !imageUploading &&
    readyAudios.length > 0 &&
    readyAudios.every((a) => a.metadata.title.trim()) &&
    !submitting;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!canSubmit || !imagePath) return;

    setSubmitting(true);
    setError(null);

    try {
      const res = await fetch("/api/jobs", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          imagePath,
          items: readyAudios.map((item) => ({
            audioPath: item.path!,
            audioFilename: item.file.name,
            metadata: item.metadata,
          })),
        }),
      });

      const data = await res.json();
      if (!res.ok) throw new Error(data.error || "Failed to create job");

      router.push(`/jobs/${data.jobId}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Submission failed");
      setSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="space-y-6">
      {quota && (
        <div className="rounded border border-gray-700 bg-surface-light px-4 py-3 text-sm text-gray-300">
          {quota.remaining} of {quota.limit} videos remaining this month
        </div>
      )}

      {error && (
        <div className="rounded border border-red-500/50 bg-red-500/10 px-4 py-3 text-sm text-red-300">
          {error}
        </div>
      )}

      <section className="rounded-lg border border-gray-700 bg-surface p-6 space-y-4">
        <h2 className="text-lg font-medium text-white">Files</h2>

        <div className="grid gap-4 md:grid-cols-2">
          <div>
            <label className="mb-2 block text-sm text-gray-400">Image</label>
            <input
              type="file"
              accept="image/*"
              onChange={handleImageChange}
              className="block w-full text-sm text-gray-300 file:mr-4 file:rounded file:border-0 file:bg-accent file:px-4 file:py-2 file:text-sm file:text-white"
            />
            <div className="mt-2 flex items-center gap-2 text-sm">
              <StatusDot ok={!!imagePath && !imageUploading} />
              <span className="text-gray-400">
                {imageUploading ? "Uploading…" : imageFile?.name || "No image selected"}
              </span>
            </div>
          </div>

          <div>
            <label className="mb-2 block text-sm text-gray-400">Audio files</label>
            <input
              type="file"
              accept="audio/*"
              multiple
              onChange={handleAudioChange}
              className="block w-full text-sm text-gray-300 file:mr-4 file:rounded file:border-0 file:bg-accent file:px-4 file:py-2 file:text-sm file:text-white"
            />
            <div className="mt-2 flex items-center gap-2 text-sm">
              <StatusDot ok={readyAudios.length > 0} />
              <span className="text-gray-400">
                {audioItems.length === 0
                  ? "No audio files selected"
                  : `${readyAudios.length} of ${audioItems.length} ready`}
              </span>
            </div>
          </div>
        </div>
      </section>

      {audioItems.length > 0 && (
        <section className="space-y-4">
          <h2 className="text-lg font-medium text-white">Video details (per audio)</h2>
          <p className="text-sm text-gray-400">
            Each audio file gets its own metadata. Title is auto-filled from the filename.
          </p>

          {audioItems.map((item, index) => (
            <div
              key={item.id}
              className="rounded-lg border border-gray-700 bg-surface p-6 space-y-4"
            >
              <div className="flex items-center justify-between">
                <div>
                  <h3 className="font-medium text-white">
                    Video {index + 1}: {item.file.name}
                  </h3>
                  {item.uploading && (
                    <p className="text-xs text-yellow-400">Uploading…</p>
                  )}
                </div>
                <button
                  type="button"
                  onClick={() => removeAudioItem(item.id)}
                  className="text-sm text-red-400 hover:text-red-300"
                >
                  Remove
                </button>
              </div>

              <div className="grid gap-4 md:grid-cols-2">
                <Field label="Title">
                  <input
                    type="text"
                    value={item.metadata.title}
                    onChange={(e) => updateItemMetadata(item.id, { title: e.target.value })}
                    className="input-field"
                    required
                  />
                </Field>

                <Field label="Category">
                  <CategorySelect
                    value={item.metadata.categoryId}
                    onChange={(v) => updateItemMetadata(item.id, { categoryId: v })}
                  />
                </Field>
              </div>

              <Field label="Description">
                <textarea
                  value={item.metadata.description}
                  onChange={(e) => updateItemMetadata(item.id, { description: e.target.value })}
                  rows={3}
                  className="input-field resize-y"
                />
              </Field>

              <Field label="Tags">
                <input
                  type="text"
                  value={item.metadata.tags}
                  onChange={(e) => updateItemMetadata(item.id, { tags: e.target.value })}
                  placeholder='Separate with spaces or commas. Use "quoted phrases" for multi-word tags.'
                  className="input-field"
                />
              </Field>

              <Field label="Privacy">
                <PrivacyToggle
                  value={item.metadata.privacy}
                  onChange={(v) => updateItemMetadata(item.id, { privacy: v })}
                />
              </Field>

              <Field label="Video size">
                <ResolutionSelect
                  value={item.metadata.resolution}
                  onChange={(v) => updateItemMetadata(item.id, { resolution: v })}
                />
              </Field>

              <div className="grid gap-3 sm:grid-cols-2">
                <Checkbox
                  label="Notify subscribers about this upload"
                  checked={item.metadata.notifySubscribers}
                  onChange={(v) => updateItemMetadata(item.id, { notifySubscribers: v })}
                />
                <Checkbox
                  label="Made For Kids?"
                  checked={item.metadata.madeForKids}
                  onChange={(v) => updateItemMetadata(item.id, { madeForKids: v })}
                />
                <Checkbox
                  label="Embeddable?"
                  checked={item.metadata.embeddable}
                  onChange={(v) => updateItemMetadata(item.id, { embeddable: v })}
                />
                <Checkbox
                  label="Creative Commons?"
                  checked={item.metadata.creativeCommons}
                  onChange={(v) => updateItemMetadata(item.id, { creativeCommons: v })}
                />
                <Checkbox
                  label="Include s2yt watermark?"
                  checked={item.metadata.includeWatermark}
                  onChange={() => {}}
                  disabled
                />
              </div>
            </div>
          ))}
        </section>
      )}

      <p className="text-sm text-accent">
        Upgrade your account to remove watermarks, go ad-free, and unlock advanced settings.
      </p>

      <button
        type="submit"
        disabled={!canSubmit}
        className="w-full rounded bg-accent px-6 py-3 font-medium text-white transition-colors hover:bg-accent-hover disabled:cursor-not-allowed disabled:opacity-50"
      >
        {submitting
          ? "Creating videos…"
          : `Create ${readyAudios.length || ""} Video${readyAudios.length !== 1 ? "s" : ""}`}
      </button>
    </form>
  );
}

function StatusDot({ ok }: { ok: boolean }) {
  return (
    <span
      className={`inline-block h-3 w-3 rounded-full ${ok ? "bg-green-500" : "bg-red-500"}`}
    />
  );
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div>
      <label className="mb-1 block text-sm text-gray-400">{label}</label>
      {children}
    </div>
  );
}

function Checkbox({
  label,
  checked,
  onChange,
  disabled,
}: {
  label: string;
  checked: boolean;
  onChange: (v: boolean) => void;
  disabled?: boolean;
}) {
  return (
    <label className={`flex items-center gap-2 text-sm text-gray-300 ${disabled ? "opacity-60" : ""}`}>
      <input
        type="checkbox"
        checked={checked}
        onChange={(e) => onChange(e.target.checked)}
        disabled={disabled}
        className="rounded border-gray-600 bg-surface-light text-accent focus:ring-accent"
      />
      {label}
    </label>
  );
}
