"use client";

import { useRouter } from "next/navigation";
import { useState } from "react";
import { Download, FileText, Play, X } from "lucide-react";
import { toast } from "sonner";
import type { FileDto, ToolResponseDto } from "@use2pdf/shared-types";
import { FileUploadDropzone } from "@/components/file-upload-dropzone";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { apiFetch, ApiRequestError, downloadFile } from "@/lib/api-client";
import { useAuth } from "@/lib/auth-context";
import { formatBytes } from "@/lib/format";
import type { ToolConfig } from "@/lib/tool-configs";

export function ToolRunner({ tool }: { tool: ToolConfig }) {
  const { user, isLoading: authLoading } = useAuth();
  const router = useRouter();

  const [files, setFiles] = useState<FileDto[]>([]);
  const [options, setOptions] = useState<Record<string, string>>(() => {
    const defaults: Record<string, string> = {};
    for (const field of tool.fields) {
      if (field.defaultValue !== undefined) defaults[field.name] = String(field.defaultValue);
    }
    return defaults;
  });
  const [isRunning, setIsRunning] = useState(false);
  const [result, setResult] = useState<ToolResponseDto | null>(null);

  function handleUploaded(newFiles: FileDto[]) {
    setFiles((prev) => (tool.multiFile ? [...prev, ...newFiles] : newFiles.slice(0, 1)));
    setResult(null);
  }

  async function handleRun() {
    if (!user) {
      toast.info("Log in to use this tool");
      router.push(`/login?next=/tools/${tool.slug}`);
      return;
    }
    if (files.length === 0) {
      toast.error("Upload a file first");
      return;
    }
    for (const field of tool.fields) {
      if (field.required && !options[field.name]?.trim()) {
        toast.error(`${field.label} is required`);
        return;
      }
    }

    const body: Record<string, unknown> = { ...options };
    // Drop empty optional fields so zod defaults/optionals apply server-side.
    for (const key of Object.keys(body)) {
      if (body[key] === "") delete body[key];
    }
    if (tool.fileIdParam === "fileIds") {
      body.fileIds = files.map((f) => f.id);
    } else {
      body.fileId = files[0].id;
    }

    setIsRunning(true);
    setResult(null);
    try {
      const data = await apiFetch<ToolResponseDto>(tool.endpoint, { method: "POST", body });
      setResult(data);
      toast.success(`${tool.name} finished`);
    } catch (err) {
      toast.error(err instanceof ApiRequestError ? err.message : "Operation failed");
    } finally {
      setIsRunning(false);
    }
  }

  async function handleDownload(file: ToolResponseDto["outputFiles"][number]) {
    try {
      await downloadFile(file.id, file.originalName);
    } catch (err) {
      toast.error(err instanceof ApiRequestError ? err.message : "Download failed");
    }
  }

  return (
    <div className="space-y-6">
      {user || authLoading ? (
        <FileUploadDropzone onUploaded={handleUploaded} accept={tool.accept} multiple={tool.multiFile} />
      ) : (
        <Card>
          <CardContent className="py-10 text-center">
            <p className="font-medium text-slate-900 dark:text-slate-100">
              Log in to use {tool.name} — it&apos;s free
            </p>
            <Button className="mt-4" onClick={() => router.push(`/login?next=/tools/${tool.slug}`)}>
              Log in
            </Button>
          </CardContent>
        </Card>
      )}

      {files.length > 0 && (
        <Card>
          <CardHeader>
            <CardTitle>
              {files.length === 1 ? files[0].originalName : `${files.length} files selected`}
            </CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            {files.length > 1 && (
              <ul className="space-y-1">
                {files.map((f) => (
                  <li key={f.id} className="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-300">
                    <FileText className="h-4 w-4 shrink-0 text-red-500" />
                    <span className="truncate">{f.originalName}</span>
                    <span className="text-slate-400">{formatBytes(f.sizeBytes)}</span>
                    <button
                      type="button"
                      aria-label={`Remove ${f.originalName}`}
                      className="ml-auto text-slate-400 hover:text-red-600"
                      onClick={() => setFiles((prev) => prev.filter((x) => x.id !== f.id))}
                    >
                      <X className="h-4 w-4" />
                    </button>
                  </li>
                ))}
              </ul>
            )}

            {tool.fields.length > 0 && (
              <div className="grid gap-4 sm:grid-cols-2">
                {tool.fields.map((field) =>
                  field.type === "select" ? (
                    <div key={field.name} className="space-y-1.5">
                      <label
                        htmlFor={`field-${field.name}`}
                        className="block text-sm font-medium text-slate-700 dark:text-slate-300"
                      >
                        {field.label}
                      </label>
                      <select
                        id={`field-${field.name}`}
                        className="block h-10 w-full rounded-md border border-slate-300 bg-white px-3 text-sm text-slate-900 focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
                        value={options[field.name] ?? ""}
                        onChange={(e) => setOptions((prev) => ({ ...prev, [field.name]: e.target.value }))}
                      >
                        {field.options?.map((opt) => (
                          <option key={opt.value} value={opt.value}>
                            {opt.label}
                          </option>
                        ))}
                      </select>
                      {field.help && <p className="text-xs text-slate-400">{field.help}</p>}
                    </div>
                  ) : (
                    <div key={field.name} className="space-y-1.5">
                      <Input
                        label={field.label}
                        type={field.type}
                        placeholder={field.placeholder}
                        min={field.min}
                        max={field.max}
                        step={field.step}
                        value={options[field.name] ?? ""}
                        onChange={(e) => setOptions((prev) => ({ ...prev, [field.name]: e.target.value }))}
                      />
                      {field.help && <p className="text-xs text-slate-400">{field.help}</p>}
                    </div>
                  ),
                )}
              </div>
            )}

            <Button onClick={handleRun} isLoading={isRunning} className="w-full sm:w-auto">
              <Play className="h-4 w-4" />
              Run {tool.shortName}
            </Button>
          </CardContent>
        </Card>
      )}

      {result && (
        <Card className="border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950">
          <CardHeader>
            <CardTitle className="text-green-900 dark:text-green-200">
              Done — {result.outputFiles.length} file{result.outputFiles.length > 1 ? "s" : ""} ready
            </CardTitle>
          </CardHeader>
          <CardContent>
            <ul className="space-y-2">
              {result.outputFiles.map((file) => (
                <li key={file.id} className="flex items-center justify-between gap-3">
                  <div className="min-w-0">
                    <p className="truncate text-sm font-medium text-green-900 dark:text-green-100">
                      {file.originalName}
                    </p>
                    <p className="text-xs text-green-700 dark:text-green-300">{formatBytes(file.sizeBytes)}</p>
                  </div>
                  <Button size="sm" onClick={() => handleDownload(file)}>
                    <Download className="h-4 w-4" />
                    Download
                  </Button>
                </li>
              ))}
            </ul>
          </CardContent>
        </Card>
      )}
    </div>
  );
}
