"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Edit2, Search, Trash2, X } from "lucide-react";
import { useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useAuth } from "@/components/auth";
import { apiDelete, apiGet, apiSend, Entity, Paginated } from "@/lib/api";

export type FieldOption = { label: string; value: string };
export type FieldConfig = {
  name: string;
  label: string;
  type?: "text" | "email" | "number" | "date" | "textarea" | "select";
  required?: boolean;
  options?: FieldOption[];
};
export type ColumnConfig<T> = { key: keyof T; label: string };

function valueForInput(value: unknown) {
  return value === null || value === undefined ? "" : String(value);
}

export function CrudPage<T extends Entity>({
  title,
  subtitle,
  endpoint,
  columns,
  fields,
  schema,
  emptyValues
}: {
  title: string;
  subtitle: string;
  endpoint: string;
  columns: ColumnConfig<T>[];
  fields: FieldConfig[];
  schema: z.ZodTypeAny;
  emptyValues: Record<string, unknown>;
}) {
  const { token } = useAuth();
  const client = useQueryClient();
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState("");
  const [editing, setEditing] = useState<T | null>(null);
  const [open, setOpen] = useState(false);
  const pageSize = 10;
  const queryPath = `${endpoint}?page=${page}&page_size=${pageSize}&search=${encodeURIComponent(search)}`;
  const form = useForm<Record<string, unknown>>({
    resolver: zodResolver(schema),
    defaultValues: emptyValues
  });

  const query = useQuery({
    queryKey: [endpoint, page, pageSize, search, token],
    queryFn: () => apiGet<Paginated<T>>(queryPath, token ?? ""),
    enabled: Boolean(token)
  });

  const totalPages = Math.max(1, Math.ceil((query.data?.total ?? 0) / pageSize));
  const invalidate = () => client.invalidateQueries({ queryKey: [endpoint] });

  const saveMutation = useMutation({
    mutationFn: (values: Record<string, unknown>) => {
      const cleaned = Object.fromEntries(
        Object.entries(values).map(([key, value]) => [key, value === "" ? null : value])
      );
      return apiSend<T>(editing ? `${endpoint}/${editing.id}` : endpoint, token ?? "", editing ? "PUT" : "POST", cleaned);
    },
    onSuccess: () => {
      setOpen(false);
      setEditing(null);
      form.reset(emptyValues);
      invalidate();
    }
  });

  const deleteMutation = useMutation({
    mutationFn: (item: T) => apiDelete(`${endpoint}/${item.id}`, token ?? ""),
    onSuccess: invalidate
  });

  const rows = useMemo(() => query.data?.items ?? [], [query.data]);

  function startCreate() {
    setEditing(null);
    form.reset(emptyValues);
    setOpen(true);
  }

  function startEdit(item: T) {
    setEditing(item);
    form.reset(Object.fromEntries(Object.keys(emptyValues).map((key) => [key, valueForInput(item[key as keyof T])])));
    setOpen(true);
  }

  return (
    <div className="space-y-6">
      <header className="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
        <div>
          <h1 className="text-3xl font-semibold text-text">{title}</h1>
          <p className="mt-2 text-text-light">{subtitle}</p>
        </div>
        <button onClick={startCreate} className="btn btn-primary h-12">Neu</button>
      </header>

      <div className="flex items-center gap-3 rounded-lg border border-border bg-surface px-4 py-3 shadow-soft">
        <Search className="h-5 w-5 text-primary" />
        <input
          value={search}
          onChange={(event) => {
            setPage(1);
            setSearch(event.target.value);
          }}
          placeholder="Suchen"
          className="h-9 flex-1 bg-transparent outline-none"
        />
      </div>

      <section className="overflow-hidden rounded-lg border border-border bg-surface shadow-soft">
        <div className="overflow-x-auto">
          <table className="min-w-full text-left text-sm">
            <thead className="bg-background text-xs uppercase text-text-light">
              <tr>
                {columns.map((column) => <th key={String(column.key)} className="px-5 py-4">{column.label}</th>)}
                <th className="px-5 py-4 text-right">Aktionen</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-border">
              {rows.map((item) => (
                <tr key={item.id} className="hover:bg-accent/10">
                  {columns.map((column) => <td key={String(column.key)} className="whitespace-nowrap px-5 py-4">{valueForInput(item[column.key])}</td>)}
                  <td className="px-5 py-4">
                    <div className="flex justify-end gap-2">
                      <button aria-label="Bearbeiten" title="Bearbeiten" onClick={() => startEdit(item)} className="icon-btn text-primary-dark"><Edit2 className="h-4 w-4" /></button>
                      <button aria-label="Loeschen" title={deleteMutation.isPending ? "Loeschen laeuft..." : "Loeschen"} disabled={deleteMutation.isPending} onClick={() => deleteMutation.mutate(item)} className="icon-btn text-danger">{deleteMutation.isPending ? <span className="spinner" /> : <Trash2 className="h-4 w-4" />}</button>
                    </div>
                  </td>
                </tr>
              ))}
              {!query.isLoading && rows.length === 0 && (
                <tr><td colSpan={columns.length + 1} className="px-5 py-10 text-center text-text-light">Keine Datensaetze gefunden.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </section>

      <footer className="flex items-center justify-between text-sm text-text-light">
        <span>{query.data?.total ?? 0} Datensaetze</span>
        <div className="flex items-center gap-3">
          <button disabled={page <= 1} title={page <= 1 ? "Erste Seite erreicht" : undefined} onClick={() => setPage((value) => value - 1)} className="btn btn-secondary">Zurueck</button>
          <span>Seite {page} von {totalPages}</span>
          <button disabled={page >= totalPages} title={page >= totalPages ? "Letzte Seite erreicht" : undefined} onClick={() => setPage((value) => value + 1)} className="btn btn-secondary">Weiter</button>
        </div>
      </footer>

      {open && (
        <div className="fixed inset-0 z-50 flex items-end bg-black/20 p-3 sm:items-center sm:justify-center">
          <form onSubmit={form.handleSubmit((values) => saveMutation.mutate(values))} className="max-h-[92vh] w-full max-w-3xl overflow-y-auto rounded-lg bg-surface p-6 shadow-soft">
            <div className="mb-5 flex items-center justify-between">
              <h2 className="text-xl font-semibold">{editing ? "Bearbeiten" : "Neu"}</h2>
              <button type="button" onClick={() => setOpen(false)} className="icon-btn"><X className="h-4 w-4" /></button>
            </div>
            <div className="grid gap-4 sm:grid-cols-2">
              {fields.map((field) => (
                <label key={field.name} className={field.type === "textarea" ? "sm:col-span-2" : ""}>
                  <span className="text-sm font-medium">{field.label}</span>
                  {field.type === "select" ? (
                    <select {...form.register(field.name)} className="mt-2 h-11 w-full rounded-lg border border-border px-3">
                      <option value="">Bitte waehlen</option>
                      {field.options?.map((option) => <option key={option.value} value={option.value}>{option.label}</option>)}
                    </select>
                  ) : field.type === "textarea" ? (
                    <textarea {...form.register(field.name)} className="mt-2 min-h-24 w-full rounded-lg border border-border px-3 py-2" />
                  ) : (
                    <input type={field.type ?? "text"} {...form.register(field.name)} className="mt-2 h-11 w-full rounded-lg border border-border px-3" />
                  )}
                  {form.formState.errors[field.name] && <span className="mt-1 block text-xs text-danger">Bitte gueltig ausfuellen.</span>}
                </label>
              ))}
            </div>
            {saveMutation.isError && <p className="mt-4 text-sm text-danger">Speichern fehlgeschlagen. Bitte Eingaben pruefen.</p>}
            <div className="mt-6 flex justify-end gap-3">
              <button type="button" onClick={() => setOpen(false)} className="btn btn-secondary">Abbrechen</button>
              <button type="submit" disabled={saveMutation.isPending} title={saveMutation.isPending ? "Speichern laeuft..." : undefined} className="btn btn-primary">{saveMutation.isPending ? <span className="spinner" /> : null}{saveMutation.isPending ? "Speichern..." : "Speichern"}</button>
            </div>
          </form>
        </div>
      )}
    </div>
  );
}
