"use client";

import { useState, useRef } from "react";
import { z } from "zod";
import { Upload } from "lucide-react";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import type { ProgrammingBlock, RotationPolicy } from "@/lib/types";

// ---------------------------------------------------------------------------
// Import schema — lenient so LLM output and community exports both work
// ---------------------------------------------------------------------------

const importBlockSchema = z.object({
  id: z.string().optional(),
  name: z.string().default("Unnamed block"),
  start_time: z
    .string()
    .regex(/^\d{2}:\d{2}(:\d{2})?$/, "start_time must be HH:MM or HH:MM:SS")
    .transform((t) => (t.length === 5 ? t + ":00" : t)),
  duration_mins: z.number().int().min(1, "duration_mins must be ≥ 1"),
  content: z.discriminatedUnion("type", [
    z.object({
      type: z.literal("algorithmic"),
      filter: z.object({
        content_type: z.enum(["movie", "episode", "short"]).nullable().optional(),
        genres: z.array(z.string()).default([]),
        decade: z.number().nullable().optional(),
        tags: z.array(z.string()).default([]),
        min_duration_secs: z.number().nullable().optional(),
        max_duration_secs: z.number().nullable().optional(),
        collections: z.array(z.string()).default([]),
      }),
      strategy: z.enum(["best_fit", "sequential", "random", "alternating", "weighted", "marathon"]).default("random"),
    }),
    z.object({
      type: z.literal("manual"),
      items: z.array(z.string()).default([]),
    }),
  ]),
});

const rotationPolicySchema = z
  .object({
    cooldown_days: z.number().int().min(0).nullable().optional(),
    cooldown_generations: z.number().int().min(0).nullable().optional(),
    min_available_ratio: z.number().min(0).max(1).default(0.1),
  })
  .default({ min_available_ratio: 0.1 });

// Accept blocks at top level OR nested under schedule_config (matches our own export format)
const importSchema = z
  .object({
    name: z.string().default("Imported Channel"),
    description: z.string().optional(),
    timezone: z.string().default("UTC"),
    blocks: z.array(importBlockSchema).optional(),
    schedule_config: z.object({ blocks: z.array(importBlockSchema).optional() }).optional(),
    rotation_policy: rotationPolicySchema,
  })
  .transform((d) => ({
    name: d.name,
    description: d.description,
    timezone: d.timezone,
    blocks: (d.blocks ?? d.schedule_config?.blocks ?? []).map((b) => ({
      ...b,
      id: b.id ?? crypto.randomUUID(),
    })) as ProgrammingBlock[],
    rotation_policy: d.rotation_policy as RotationPolicy,
  }));

export type ChannelImportData = z.output<typeof importSchema>;

export function parseChannelJson(text: string): { data: ChannelImportData } | { error: string } {
  let raw: unknown;
  try {
    raw = JSON.parse(text);
  } catch {
    return { error: "Invalid JSON — check for missing commas, brackets, or quotes." };
  }
  const result = importSchema.safeParse(raw);
  if (!result.success) {
    return { error: result.error.issues[0].message };
  }
  return { data: result.data };
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

interface ImportChannelDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSubmit: (data: ChannelImportData) => void;
  isPending: boolean;
  error?: string | null;
}

export function ImportChannelDialog({
  open,
  onOpenChange,
  onSubmit,
  isPending,
  error,
}: ImportChannelDialogProps) {
  const [text, setText] = useState("");
  const [parseError, setParseError] = useState<string | null>(null);
  const [parsed, setParsed] = useState<ChannelImportData | null>(null);
  const [dragging, setDragging] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const processText = (value: string) => {
    setText(value);
    if (!value.trim()) {
      setParsed(null);
      setParseError(null);
      return;
    }
    const result = parseChannelJson(value);
    if ("error" in result) {
      setParsed(null);
      setParseError(result.error);
    } else {
      setParsed(result.data);
      setParseError(null);
    }
  };

  const handleFile = (file: File) => {
    if (!file.name.endsWith(".json") && file.type !== "application/json") {
      setParseError("Please upload a .json file.");
      return;
    }
    file.text().then(processText);
  };

  const handleClose = () => {
    if (!isPending) {
      onOpenChange(false);
      setText("");
      setParsed(null);
      setParseError(null);
    }
  };

  return (
    <Dialog open={open} onOpenChange={handleClose}>
      <DialogContent className="bg-zinc-900 border-zinc-800 text-zinc-100 sm:max-w-lg">
        <DialogHeader>
          <DialogTitle>Import channel</DialogTitle>
        </DialogHeader>

        <div className="space-y-3 py-1">
          <p className="text-xs text-zinc-500">
            Paste JSON or upload a file. Works with exported channel configs or LLM-generated blocks.
          </p>

          {/* Textarea + drag-and-drop */}
          <div
            onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
            onDragLeave={() => setDragging(false)}
            onDrop={(e) => {
              e.preventDefault();
              setDragging(false);
              const file = e.dataTransfer.files[0];
              if (file) handleFile(file);
            }}
            className={`relative rounded-md border transition-colors ${
              dragging ? "border-zinc-500 bg-zinc-800" : "border-zinc-700"
            }`}
          >
            <textarea
              value={text}
              onChange={(e) => processText(e.target.value)}
              rows={12}
              placeholder={`{\n  "name": "My Channel",\n  "timezone": "UTC",\n  "blocks": [\n    {\n      "name": "Evening Movies",\n      "start_time": "20:00",\n      "duration_mins": 180,\n      "content": {\n        "type": "algorithmic",\n        "filter": { "genres": ["Drama"] },\n        "strategy": "random"\n      }\n    }\n  ]\n}`}
              spellCheck={false}
              className="w-full resize-none rounded-md bg-transparent px-3 py-2.5 font-mono text-xs text-zinc-100 placeholder:text-zinc-700 focus:outline-none"
            />
            {dragging && (
              <div className="pointer-events-none absolute inset-0 flex items-center justify-center rounded-md bg-zinc-800/80">
                <p className="text-sm text-zinc-300">Drop JSON file here</p>
              </div>
            )}
          </div>

          {/* File upload */}
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={() => fileInputRef.current?.click()}
              className="flex items-center gap-1.5 rounded-md border border-zinc-700 bg-zinc-800 px-3 py-1.5 text-xs text-zinc-400 hover:border-zinc-600 hover:text-zinc-200 transition-colors"
            >
              <Upload className="size-3" />
              Upload .json file
            </button>
            <input
              ref={fileInputRef}
              type="file"
              accept=".json,application/json"
              className="hidden"
              onChange={(e) => { const f = e.target.files?.[0]; if (f) handleFile(f); }}
            />
            {parsed && (
              <span className="text-xs text-zinc-500">
                Drag-and-drop a file or paste JSON above
              </span>
            )}
          </div>

          {/* Validation feedback */}
          {parseError && (
            <p className="rounded-md bg-red-950/40 px-3 py-2 text-xs text-red-400 border border-red-900/50">
              {parseError}
            </p>
          )}

          {parsed && (
            <div className="rounded-md border border-zinc-700 bg-zinc-800/60 px-3 py-2.5 space-y-1">
              <p className="text-xs font-medium text-zinc-300">{parsed.name}</p>
              <div className="flex flex-wrap gap-x-4 gap-y-0.5 text-[11px] text-zinc-500">
                {parsed.description && <span>{parsed.description}</span>}
                <span>{parsed.timezone}</span>
                <span>{parsed.blocks.length} {parsed.blocks.length === 1 ? "block" : "blocks"}</span>
              </div>
              {parsed.blocks.length > 0 && (
                <ul className="mt-1 space-y-0.5">
                  {parsed.blocks.slice(0, 5).map((b, i) => (
                    <li key={i} className="text-[11px] text-zinc-600">
                      · {b.name} — {b.start_time.slice(0, 5)}, {b.duration_mins}m
                    </li>
                  ))}
                  {parsed.blocks.length > 5 && (
                    <li className="text-[11px] text-zinc-700">
                      … and {parsed.blocks.length - 5} more
                    </li>
                  )}
                </ul>
              )}
            </div>
          )}

          {error && (
            <p className="text-xs text-red-400">{error}</p>
          )}
        </div>

        <DialogFooter>
          <Button type="button" variant="ghost" onClick={handleClose} disabled={isPending}>
            Cancel
          </Button>
          <Button
            onClick={() => parsed && onSubmit(parsed)}
            disabled={!parsed || isPending}
          >
            {isPending ? "Importing…" : "Import channel"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
