"use client";

import { useMemo, useState } from "react";
import type { FormEvent, ReactNode } from "react";

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { Role } from "@/types/rbac";
import type { User, UserPayload, UserRole } from "@/types/user";

const emptyForm: UserPayload = {
  first_name: "",
  last_name: "",
  username: "",
  email: "",
  role: "support",
  role_id: undefined,
  is_active: true,
  password: "",
};

type Props = {
  open: boolean;
  user?: User | null;
  pending?: boolean;
  serverError?: string;
  roles: Role[];
  onOpenChange: (open: boolean) => void;
  onSubmit: (payload: UserPayload) => Promise<void>;
};

export default function UserFormDialog({
  open,
  user,
  pending = false,
  serverError,
  roles,
  onOpenChange,
  onSubmit,
}: Props) {
  const isEditing = Boolean(user);
  const initialForm = user
    ? {
        first_name: user.first_name,
        last_name: user.last_name,
        username: user.username,
        email: user.email,
        role: user.role,
        role_id: user.role_id,
        is_active: user.is_active,
        password: "",
      }
    : {
        ...emptyForm,
        role: roles[0]?.name ?? "support",
        role_id: roles[0]?.id,
      };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-2xl">
        {open && (
          <UserForm
            key={user?.id ?? "new"}
            initialForm={initialForm}
            isEditing={isEditing}
            pending={pending}
            serverError={serverError}
            roles={roles}
            onCancel={() => onOpenChange(false)}
            onSubmit={onSubmit}
          />
        )}
      </DialogContent>
    </Dialog>
  );
}

function UserForm({
  initialForm,
  isEditing,
  pending,
  serverError,
  roles,
  onCancel,
  onSubmit,
}: {
  initialForm: UserPayload;
  isEditing: boolean;
  pending: boolean;
  serverError?: string;
  roles: Role[];
  onCancel: () => void;
  onSubmit: (payload: UserPayload) => Promise<void>;
}) {
  const [form, setForm] = useState<UserPayload>(initialForm);

  const errors = useMemo(() => {
    return {
      username: form.username.trim().length < 3
        ? "Mindestens 3 Zeichen"
        : "",
      email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)
        ? ""
        : "Gültige E-Mail erforderlich",
      password: !isEditing && (form.password?.length ?? 0) < 8
        ? "Mindestens 8 Zeichen"
        : "",
    };
  }, [form.email, form.password, form.username, isEditing]);

  const isValid = Object.values(errors).every((error) => !error);

  function updateField<K extends keyof UserPayload>(key: K, value: UserPayload[K]) {
    setForm((current) => ({
      ...current,
      [key]: value,
    }));
  }

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    if (!isValid) {
      return;
    }

    const payload = {
      ...form,
      password: form.password?.trim() || undefined,
    };

    await onSubmit(payload);
  }

  return (
        <form onSubmit={handleSubmit} className="space-y-5">
          <DialogHeader>
            <DialogTitle>{isEditing ? "Benutzer bearbeiten" : "Benutzer erstellen"}</DialogTitle>
            <DialogDescription>
              Stammdaten, Rolle und Status des Benutzers verwalten.
            </DialogDescription>
          </DialogHeader>

          <div className="grid gap-4 sm:grid-cols-2">
            <Field label="Vorname">
              <Input
                value={form.first_name}
                onChange={(event) => updateField("first_name", event.target.value)}
              />
            </Field>

            <Field label="Nachname">
              <Input
                value={form.last_name}
                onChange={(event) => updateField("last_name", event.target.value)}
              />
            </Field>

            <Field label="Benutzername" error={errors.username}>
              <Input
                value={form.username}
                aria-invalid={Boolean(errors.username)}
                onChange={(event) => updateField("username", event.target.value)}
              />
            </Field>

            <Field label="E-Mail" error={errors.email}>
              <Input
                type="email"
                value={form.email}
                aria-invalid={Boolean(errors.email)}
                onChange={(event) => updateField("email", event.target.value)}
              />
            </Field>

            <Field label="Rolle">
              <select
                value={form.role_id ?? ""}
                onChange={(event) => {
                  const role = roles.find((item) => item.id === Number(event.target.value));
                  updateField("role_id", role?.id);
                  updateField("role", (role?.name ?? "") as UserRole);
                }}
                className="h-8 w-full rounded-lg border border-input bg-transparent px-2.5 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
              >
                {roles.map((role) => (
                  <option key={role.id} value={role.id}>
                    {role.display_name}
                  </option>
                ))}
              </select>
            </Field>

            <Field label="Status">
              <label className="flex h-8 items-center gap-2 rounded-lg border px-2.5 text-sm">
                <input
                  type="checkbox"
                  checked={form.is_active}
                  onChange={(event) => updateField("is_active", event.target.checked)}
                />
                Aktiv
              </label>
            </Field>

            <Field
              label={isEditing ? "Neues Passwort" : "Passwort"}
              error={errors.password}
            >
              <Input
                type="password"
                value={form.password ?? ""}
                aria-invalid={Boolean(errors.password)}
                onChange={(event) => updateField("password", event.target.value)}
              />
            </Field>
          </div>

          {serverError && <p className="text-sm text-red-600">{serverError}</p>}

          <DialogFooter>
            <Button
              type="button"
              variant="outline"
              onClick={onCancel}
              disabled={pending}
            >
              Abbrechen
            </Button>
            <Button type="submit" disabled={!isValid || pending}>
              {pending ? "Speichern..." : "Speichern"}
            </Button>
          </DialogFooter>
        </form>
  );
}

function Field({
  label,
  error,
  children,
}: {
  label: string;
  error?: string;
  children: ReactNode;
}) {
  return (
    <div className="space-y-1.5">
      <Label>{label}</Label>
      {children}
      {error && <p className="text-xs text-red-600">{error}</p>}
    </div>
  );
}
