import { useState, type ReactNode } from "react";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { toast } from "sonner";

export type Field = {
  name: string;
  label: string;
  type?: "text" | "password" | "select" | "textarea" | "date" | "photo" | "file" | undefined;
  options?: string[] | ((values: Record<string, string>) => string[]);
  optional?: boolean | undefined;
  placeholder?: string | undefined;
  defaultValue?: string | undefined;
  showIf?: ((values: Record<string, string>) => boolean) | undefined;
};

export const val = (v: Record<string, string>, key: string) => (v[key] ?? "").trim();

type Props = {
  title: string;
  description?: string;
  fields: Field[];
  trigger: ReactNode;
  submitLabel?: string;
  onSubmit: (values: Record<string, string>) => void;
};

export function FormDialog({
  title,
  description,
  fields,
  trigger,
  submitLabel = "Simpan",
  onSubmit,
}: Props) {
  const [open, setOpen] = useState(false);

  const buildInitial = () => {
    const next: Record<string, string> = {};
    for (const f of fields) {
      const opts = typeof f.options === "function" ? f.options(next) : f.options;
      next[f.name] = f.defaultValue ?? (f.type === "select" ? (opts?.[0] ?? "") : "");
    }
    return next;
  };
  const [values, setValues] = useState<Record<string, string>>(buildInitial);

  const handleOpenChange = (next: boolean) => {
    if (next) setValues(buildInitial());
    setOpen(next);
  };

  const visibleFields = fields.filter((f) => (f.showIf ? f.showIf(values) : true));

  const submit = () => {
    const missing = visibleFields.find((f) => !f.optional && !String(values[f.name] ?? "").trim());
    if (missing) {
      toast.error("Data belum lengkap", { description: `${missing.label} wajib diisi.` });
      return;
    }
    onSubmit(values);
    setOpen(false);
  };

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogTrigger asChild>{trigger}</DialogTrigger>
      <DialogContent className="max-h-[85vh] overflow-y-auto sm:max-w-lg">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          {description ? <DialogDescription>{description}</DialogDescription> : null}
        </DialogHeader>
        <div className="grid gap-4 py-2">
          {visibleFields.map((f) => (
            <div key={f.name} className="grid gap-2">
              <Label htmlFor={f.name}>
                {f.label}
                {f.optional ? <span className="text-muted-foreground"> (opsional)</span> : null}
              </Label>
              {f.type === "select" ? (
                <select
                  id={f.name}
                  value={values[f.name] ?? ""}
                  onChange={(e) => setValues((v) => ({ ...v, [f.name]: e.target.value }))}
                  className="border-input bg-background focus-visible:ring-ring h-10 rounded-md border px-3 text-sm focus-visible:ring-2 focus-visible:outline-none"
                >
                  {f.optional ? <option value="">-- Tidak dipilih --</option> : null}
                  {(() => {
                    const opts = typeof f.options === "function" ? f.options(values) : f.options;
                    return (opts ?? []).map((o) => (
                      <option key={o} value={o}>
                        {o}
                      </option>
                    ));
                  })()}
                </select>
              ) : f.type === "photo" ? (
                <div className="grid gap-2">
                  <Input
                    id={f.name}
                    type="file"
                    accept="image/*"
                    capture="environment"
                    onChange={(e) => {
                      const file = e.target.files?.[0];
                      if (!file) return;
                      if (file.size > 3 * 1024 * 1024) {
                        toast.error("Ukuran foto maksimal 3 MB");
                        return;
                      }
                      const reader = new FileReader();
                      reader.onload = () =>
                        setValues((v) => ({ ...v, [f.name]: String(reader.result ?? "") }));
                      reader.readAsDataURL(file);
                    }}
                  />
                  {values[f.name] ? (
                    <img
                      src={values[f.name]}
                      alt="Pratinjau foto tamu"
                      className="border-border h-32 w-32 rounded-md border object-cover"
                    />
                  ) : null}
                </div>
              ) : f.type === "file" ? (
                <div className="grid gap-2">
                  <Input
                    id={f.name}
                    type="file"
                    accept="image/*,application/pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt"
                    onChange={(e) => {
                      const file = e.target.files?.[0];
                      if (!file) return;
                      if (file.size > 5 * 1024 * 1024) {
                        toast.error("Ukuran file maksimal 5 MB");
                        return;
                      }
                      const reader = new FileReader();
                      reader.onload = () =>
                        setValues((v) => ({
                          ...v,
                          [f.name]: String(reader.result ?? ""),
                          [`${f.name}__nama`]: file.name,
                        }));
                      reader.readAsDataURL(file);
                    }}
                  />
                  {values[`${f.name}__nama`] ? (
                    <p className="text-muted-foreground text-xs">
                      File dipilih: {values[`${f.name}__nama`]}
                    </p>
                  ) : null}
                </div>
              ) : f.type === "textarea" ? (
                <Textarea
                  id={f.name}
                  placeholder={f.placeholder}
                  value={values[f.name] ?? ""}
                  onChange={(e) => setValues((v) => ({ ...v, [f.name]: e.target.value }))}
                />
              ) : (
                <Input
                  id={f.name}
                  type={f.type === "password" ? "password" : f.type === "date" ? "date" : "text"}
                  placeholder={f.placeholder}
                  value={values[f.name] ?? ""}
                  onChange={(e) => setValues((v) => ({ ...v, [f.name]: e.target.value }))}
                />
              )}
            </div>
          ))}
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={() => setOpen(false)}>
            Batal
          </Button>
          <Button onClick={submit}>{submitLabel}</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}