"use client";

import Link from "next/link";
import { useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { Button, Spinner, useToast } from "@/components/ui";
import { useSession } from "@/components/session-provider";
import { api, uploadFile } from "@/lib/api-client";
import { CATEGORIES, VISIBILITIES } from "@/lib/constants";
import { formatDuration } from "@/lib/format";

export default function UploadPage() {
  const { channel, user } = useSession();
  const router = useRouter();
  const { toast, toastNode } = useToast();
  const fileInput = useRef<HTMLInputElement | null>(null);
  const [file, setFile] = useState<File | null>(null);
  const [uploadPct, setUploadPct] = useState(0);
  const [uploading, setUploading] = useState(false);
  const [analyzing, setAnalyzing] = useState(false);
  const [duration, setDuration] = useState(0);
  const [autoThumb, setAutoThumb] = useState<string | null>(null);
  const [customThumb, setCustomThumb] = useState<string | null>(null);
  const [sourceKey, setSourceKey] = useState<string | null>(null);
  const [publishing, setPublishing] = useState(false);
  const [form, setForm] = useState({
    title: "",
    description: "",
    categorySlug: "entertainment",
    tags: "",
    visibility: "public",
    isShort: false,
    isAgeRestricted: false,
    monetized: true,
    audioTrackName: "",
    scheduledFor: "",
    chapters: "",
    captions: "",
  });

  const pickFile = (chosen: File | null) => {
    setFile(chosen);
    setUploadPct(0);
    setAutoThumb(null);
    setCustomThumb(null);
    setDuration(0);
    if (!chosen) return;
    if (!form.title) setForm((prev) => ({ ...prev, title: chosen.name.replace(/\.[^.]+$/, "").replace(/[_-]+/g, " ") }));
    // Auto-generate a thumbnail frame in the browser (works with or without FFmpeg).
    const url = URL.createObjectURL(chosen);
    const video = document.createElement("video");
    video.preload = "metadata";
    video.src = url;
    video.onloadedmetadata = () => {
      setDuration(video.duration || 0);
      setForm((prev) => ({ ...prev, isShort: (video.videoHeight ?? 0) > (video.videoWidth ?? 0) }));
      video.currentTime = Math.min(3, (video.duration || 4) / 3);
    };
    video.onseeked = () => {
      try {
        const canvas = document.createElement("canvas");
        canvas.width = Math.min(1280, video.videoWidth || 1280);
        canvas.height = Math.round(canvas.width * ((video.videoHeight || 720) / (video.videoWidth || 1280)));
        canvas.getContext("2d")?.drawImage(video, 0, 0, canvas.width, canvas.height);
        setAutoThumb(canvas.toDataURL("image/jpeg", 0.82));
      } catch {
        /* cross-origin frame not drawable */
      }
      URL.revokeObjectURL(url);
    };
  };

  const startUpload = async () => {
    if (!file) return toast("Choose a video file first");
    if (!channel) return toast("Create a channel first");
    setUploading(true);
    try {
      const stored = await uploadFile(file, "video", undefined, setUploadPct);
      setSourceKey(stored.key);
      toast("Upload complete — transcoding started");
    } catch (error) {
      toast(error instanceof Error ? error.message : "Upload failed");
    } finally {
      setUploading(false);
    }
  };

  const uploadCustomThumb = async (chosen: File) => {
    try {
      const stored = await uploadFile(chosen, "image", "uploads/thumbs");
      setCustomThumb(stored.key);
    } catch (error) {
      toast(error instanceof Error ? error.message : "Thumbnail upload failed");
    }
  };

  const uploadAutoThumb = async () => {
    if (!autoThumb) return null;
    const blob = await (await fetch(autoThumb)).blob();
    const stored = await uploadFile(new File([blob], "thumb.jpg", { type: "image/jpeg" }), "image", "uploads/thumbs");
    return stored.key;
  };

  const publish = async () => {
    if (!sourceKey) return toast("Upload the video file first");
    if (!form.title.trim()) return toast("Add a title");
    setPublishing(true);
    try {
      const thumbKey = customThumb ?? (await uploadAutoThumb());
      const chapters = form.chapters
        .split("\n")
        .map((line) => {
          const [time, ...rest] = line.split(" ");
          const parts = time.split(":").map(Number);
          const seconds = parts.length === 3 ? parts[0] * 3600 + parts[1] * 60 + parts[2] : parts.length === 2 ? parts[0] * 60 + parts[1] : Number(time);
          return { time: Number.isFinite(seconds) ? seconds : 0, title: rest.join(" ") };
        })
        .filter((chapter) => chapter.title);
      const captions = form.captions
        .split("\n")
        .map((line) => {
          const [range, ...rest] = line.split(" ");
          const [start, end] = range.split("-");
          return { start: Number(start) || 0, end: Number(end) || 0, text: rest.join(" ") };
        })
        .filter((cue) => cue.text)
        .slice(0, 500);

      const video = await api<{ video: { id: string } }>("/api/videos", {
        method: "POST",
        json: {
          title: form.title,
          description: form.description,
          categorySlug: form.categorySlug,
          tags: form.tags.split(",").map((t) => t.trim()).filter(Boolean),
          visibility: form.visibility,
          isShort: form.isShort,
          isAgeRestricted: form.isAgeRestricted,
          monetized: form.monetized,
          audioTrackName: form.audioTrackName || null,
          scheduledFor: form.scheduledFor ? new Date(form.scheduledFor).toISOString() : null,
          durationSeconds: Math.round(duration),
          sourceKey,
          thumbnailKey: thumbKey ?? null,
          chapters,
          captions: captions.length ? [{ lang: "en", label: "English", cues: captions }] : [],
        },
      });
      toast("Video published — processing in the background");
      router.push(`/watch/${video.video.id}`);
    } catch (error) {
      toast(error instanceof Error ? error.message : "Could not publish");
    } finally {
      setPublishing(false);
    }
  };

  if (!user) {
    return (
      <div className="grid place-items-center py-20 text-center">
        <p className="text-sm text-muted">
          <Link href="/login" className="font-semibold text-brand">Sign in</Link> to upload videos.
        </p>
      </div>
    );
  }

  return (
    <div className="mx-auto max-w-3xl space-y-6">
      <header>
        <h1 className="text-2xl font-bold">Upload a video</h1>
        <p className="text-sm text-muted">MP4, WebM, MOV or MKV up to 512 MB. FFmpeg transcodes every upload into an adaptive HLS ladder.</p>
      </header>

      <div
        onDragOver={(event) => event.preventDefault()}
        onDrop={(event) => {
          event.preventDefault();
          pickFile(event.dataTransfer.files?.[0] ?? null);
        }}
        className="rounded-2xl border-2 border-dashed border-line p-8 text-center"
      >
        <input
          ref={fileInput}
          type="file"
          accept="video/*"
          capture={undefined}
          hidden
          onChange={(event) => pickFile(event.target.files?.[0] ?? null)}
        />
        <p className="text-5xl">📼</p>
        <p className="mt-3 text-sm font-medium">{file ? file.name : "Drag and drop a video, or choose from your device"}</p>
        <p className="text-xs text-muted">{file ? `${(file.size / 1048576).toFixed(1)} MB · ${duration ? formatDuration(duration) : "reading metadata..."}` : "Camera and gallery uploads are supported on mobile."}</p>
        <div className="mt-4 flex flex-wrap justify-center gap-2">
          <Button onClick={() => fileInput.current?.click()} variant="secondary">Choose file</Button>
          <Button onClick={() => void startUpload()} disabled={!file || uploading}>
            {uploading ? <Spinner className="!h-4 !w-4" /> : "⬆️"} Upload
          </Button>
        </div>
        {uploadPct > 0 ? (
          <div className="mx-auto mt-4 h-2 w-64 overflow-hidden rounded-full bg-chip">
            <div className="h-full bg-brand transition-all" style={{ width: `${uploadPct}%` }} />
          </div>
        ) : null}
        {sourceKey ? <p className="mt-2 text-xs text-green-500">Uploaded ✓ — transcoding runs automatically</p> : null}
      </div>

      <div className="grid gap-4 sm:grid-cols-2">
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Title</span>
          <input value={form.title} onChange={(event) => setForm({ ...form, title: event.target.value })} maxLength={200} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
        </label>
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Category</span>
          <select value={form.categorySlug} onChange={(event) => setForm({ ...form, categorySlug: event.target.value })} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm">
            {CATEGORIES.filter((c) => c.slug !== "all").map((category) => (
              <option key={category.slug} value={category.slug}>{category.name}</option>
            ))}
          </select>
        </label>
      </div>

      <label className="block space-y-1">
        <span className="text-xs font-semibold uppercase text-muted">Description</span>
        <textarea value={form.description} onChange={(event) => setForm({ ...form, description: event.target.value })} rows={4} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
      </label>

      <div className="grid gap-4 sm:grid-cols-2">
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Tags</span>
          <input value={form.tags} onChange={(event) => setForm({ ...form, tags: event.target.value })} placeholder="gaming, fps, review" className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
        </label>
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Visibility</span>
          <select value={form.visibility} onChange={(event) => setForm({ ...form, visibility: event.target.value })} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm">
            {VISIBILITIES.map((option) => (
              <option key={option.value} value={option.value}>{option.label} — {option.hint}</option>
            ))}
          </select>
        </label>
      </div>

      <div className="grid gap-4 sm:grid-cols-2">
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Schedule publishing (optional)</span>
          <input type="datetime-local" value={form.scheduledFor} onChange={(event) => setForm({ ...form, scheduledFor: event.target.value })} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
        </label>
        <label className="space-y-1">
          <span className="text-xs font-semibold uppercase text-muted">Audio track name (shorts)</span>
          <input value={form.audioTrackName} onChange={(event) => setForm({ ...form, audioTrackName: event.target.value })} placeholder="PlayTube Sound Library — Midnight Drive" className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
        </label>
      </div>

      <label className="block space-y-1">
        <span className="text-xs font-semibold uppercase text-muted">Chapters (one per line: <code>0:00 Intro</code>)</span>
        <textarea value={form.chapters} onChange={(event) => setForm({ ...form, chapters: event.target.value })} rows={3} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
      </label>

      <label className="block space-y-1">
        <span className="text-xs font-semibold uppercase text-muted">Captions (one per line: <code>0-4 Hello world</code> seconds)</span>
        <textarea value={form.captions} onChange={(event) => setForm({ ...form, captions: event.target.value })} rows={3} className="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm" />
      </label>

      <div className="space-y-2">
        <p className="text-xs font-semibold uppercase text-muted">Thumbnail</p>
        <div className="flex flex-wrap items-center gap-3">
          <div className="h-24 w-40 overflow-hidden rounded-lg bg-surface">
            {autoThumb || customThumb ? (
              // eslint-disable-next-line @next/next/no-img-element
              <img src={customThumb ? `/api/files/${customThumb}` : autoThumb!} alt="" className="h-full w-full object-cover" />
            ) : (
              <div className="grid h-full place-items-center text-xs text-muted">Auto thumbnail appears here</div>
            )}
          </div>
          <label className="cursor-pointer rounded-full bg-surface px-4 py-2 text-sm font-medium">
            Upload custom thumbnail
            <input type="file" accept="image/*" hidden onChange={(event) => { const f = event.target.files?.[0]; if (f) void uploadCustomThumb(f); }} />
          </label>
          {autoThumb ? <span className="text-xs text-muted">Auto frame captured at {Math.min(3, Math.round(duration / 3))}s</span> : null}
        </div>
      </div>

      <div className="flex flex-wrap gap-4 text-sm">
        <label className="flex items-center gap-2"><input type="checkbox" checked={form.isShort} onChange={(event) => setForm({ ...form, isShort: event.target.checked })} /> Publish as a Short</label>
        <label className="flex items-center gap-2"><input type="checkbox" checked={form.isAgeRestricted} onChange={(event) => setForm({ ...form, isAgeRestricted: event.target.checked })} /> Age restrict (18+)</label>
        <label className="flex items-center gap-2"><input type="checkbox" checked={form.monetized} onChange={(event) => setForm({ ...form, monetized: event.target.checked })} /> Enable advertising</label>
      </div>

      <div className="flex flex-wrap gap-2 border-t border-line pt-4">
        <Button onClick={() => void publish()} disabled={!sourceKey || publishing}>
          {publishing ? <Spinner className="!h-4 !w-4" /> : null} Publish now
        </Button>
        <Button
          variant="secondary"
          disabled={!sourceKey || publishing}
          onClick={async () => {
            setForm({ ...form, visibility: "draft" });
            await publish();
          }}
        >
          Save as draft
        </Button>
      </div>
      {toastNode}
    </div>
  );
}
