import { useState } from "react";
import type { SiteConfig } from "@/lib/grabber/sites";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";

type Props = {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  onAdd: (site: SiteConfig) => void;
};

const DEFAULT: SiteConfig = {
  id: "danbooru",
  name: "Danbooru",
  baseUrl: "https://danbooru.donmai.us",
  searchPath: "/posts.json",
  params: { tags: "tags", page: "page", limit: "limit" },
  postsPath: "",
  fields: {
    id: "id",
    previewUrl: "preview_file_url",
    fileUrl: "file_url",
    ext: "file_ext",
    tags: "tag_string_general",
    source: "source",
    rating: "rating",
    score: "score",
    sampleUrl: "large_file_url",
    fileSize: "file_size",
    width: "image_width",
    height: "image_height",
    md5: "md5",
    uploader: "uploader_name",
    createdAt: "created_at",
  },
};

export function AddSiteDialog({ open, onOpenChange, onAdd }: Props) {
  const [s, setS] = useState<SiteConfig>(DEFAULT);
  const [headersText, setHeadersText] = useState("");
  const [pasteSchemaText, setPasteSchemaText] = useState("");
  const [parseError, setParseError] = useState("");

  const set = <K extends keyof SiteConfig>(k: K, v: SiteConfig[K]) =>
    setS((p) => ({ ...p, [k]: v }));
  const setField = (k: keyof SiteConfig["fields"], v: string) =>
    setS((p) => ({ ...p, fields: { ...p.fields, [k]: v } }));
  const setParam = (k: keyof SiteConfig["params"], v: string) =>
    setS((p) => ({ ...p, params: { ...p.params, [k]: v } }));

  const handlePasteSchema = () => {
    setParseError("");
    if (!pasteSchemaText.trim()) return;
    try {
      const parsed = JSON.parse(pasteSchemaText);
      if (typeof parsed !== "object" || parsed === null) {
        throw new Error("Schema must be an object");
      }

      const merged: SiteConfig = {
        id: parsed.id || s.id,
        name: parsed.name || s.name,
        baseUrl: parsed.baseUrl || s.baseUrl,
        searchPath: parsed.searchPath || s.searchPath,
        params: {
          tags: parsed.params?.tags || s.params.tags,
          page: parsed.params?.page || s.params.page,
          limit: parsed.params?.limit || s.params.limit,
        },
        postsPath: typeof parsed.postsPath === "string" ? parsed.postsPath : s.postsPath,
        fields: {
          id: parsed.fields?.id || s.fields.id,
          previewUrl: parsed.fields?.previewUrl || s.fields.previewUrl,
          fileUrl: parsed.fields?.fileUrl || s.fields.fileUrl,
          ext: parsed.fields?.ext || s.fields.ext,
          tags: parsed.fields?.tags || s.fields.tags,
          source: parsed.fields?.source || s.fields.source,
          rating: parsed.fields?.rating || s.fields.rating,
          score: parsed.fields?.score || s.fields.score,
          sampleUrl: parsed.fields?.sampleUrl || s.fields.sampleUrl,
          fileSize: parsed.fields?.fileSize || s.fields.fileSize,
          width: parsed.fields?.width || s.fields.width,
          height: parsed.fields?.height || s.fields.height,
          md5: parsed.fields?.md5 || s.fields.md5,
          uploader: parsed.fields?.uploader || s.fields.uploader,
          createdAt: parsed.fields?.createdAt || s.fields.createdAt,
        },
      };

      if (parsed.headers && typeof parsed.headers === "object") {
        setHeadersText(JSON.stringify(parsed.headers, null, 2));
      }

      setS(merged);
      setPasteSchemaText("");
    } catch (e: unknown) {
      if (e instanceof Error) {
        setParseError(e.message);
      } else {
        setParseError("Failed to parse JSON");
      }
    }
  };

  const submit = () => {
    let headers: Record<string, string> | undefined;
    if (headersText.trim()) {
      try {
        headers = JSON.parse(headersText);
      } catch {
        alert("Headers must be valid JSON");
        return;
      }
    }
    onAdd({ ...s, headers });
    onOpenChange(false);
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>Add Site (schema)</DialogTitle>
        </DialogHeader>

        {/* New Paste Schema Input Box */}
        <div className="border p-3 rounded-md bg-muted/30 mb-4">
          <Label className="text-xs font-semibold mb-1 block">
            Paste Site Configuration JSON (API Support)
          </Label>
          <div className="flex gap-2">
            <Textarea
              rows={3}
              value={pasteSchemaText}
              onChange={(e) => setPasteSchemaText(e.target.value)}
              placeholder={`Paste JSON schema here, e.g.:\n{\n  "id": "danbooru",\n  "name": "Danbooru",\n  "baseUrl": "https://danbooru.donmai.us",\n  "fields": { "fileUrl": "file_url" }\n}`}
              className="font-mono text-xs flex-1"
            />
            <Button variant="secondary" size="sm" onClick={handlePasteSchema} className="self-end">
              Apply Schema
            </Button>
          </div>
          {parseError && (
            <div className="text-xs text-destructive mt-1 font-semibold">{parseError}</div>
          )}
        </div>

        <div className="grid grid-cols-2 gap-3">
          <Field label="ID (unique)">
            <Input value={s.id} onChange={(e) => set("id", e.target.value)} />
          </Field>
          <Field label="Name">
            <Input value={s.name} onChange={(e) => set("name", e.target.value)} />
          </Field>
          <Field label="Base URL">
            <Input value={s.baseUrl} onChange={(e) => set("baseUrl", e.target.value)} />
          </Field>
          <Field label="Search Path">
            <Input value={s.searchPath} onChange={(e) => set("searchPath", e.target.value)} />
          </Field>
          <Field label="tags param">
            <Input value={s.params.tags} onChange={(e) => setParam("tags", e.target.value)} />
          </Field>
          <Field label="page param">
            <Input value={s.params.page} onChange={(e) => setParam("page", e.target.value)} />
          </Field>
          <Field label="limit param">
            <Input value={s.params.limit} onChange={(e) => setParam("limit", e.target.value)} />
          </Field>
          <Field label="posts JSON path (empty = root)">
            <Input value={s.postsPath} onChange={(e) => set("postsPath", e.target.value)} />
          </Field>
          <div className="col-span-2 border-t pt-3 mt-1 text-sm font-semibold">
            Field mappings (dotted paths)
          </div>
          {(
            [
              "id",
              "previewUrl",
              "fileUrl",
              "ext",
              "tags",
              "source",
              "rating",
              "score",
              "sampleUrl",
              "fileSize",
              "width",
              "height",
              "md5",
              "uploader",
              "createdAt",
            ] as const
          ).map((k) => (
            <Field key={k} label={k}>
              <Input value={s.fields[k] ?? ""} onChange={(e) => setField(k, e.target.value)} />
            </Field>
          ))}

          <Field label="Extra headers (JSON, optional)" full>
            <Textarea
              rows={3}
              value={headersText}
              onChange={(e) => setHeadersText(e.target.value)}
              placeholder='{"User-Agent":"MyGrabber/1.0"}'
            />
          </Field>
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button onClick={submit}>Add site</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function Field({
  label,
  children,
  full,
}: {
  label: string;
  children: React.ReactNode;
  full?: boolean;
}) {
  return (
    <div className={full ? "col-span-2" : ""}>
      <Label className="text-xs mb-1 block">{label}</Label>
      {children}
    </div>
  );
}
