"use client";

import { useCallback, useEffect, useState } from "react";
import type { FormEvent } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { ArrowLeft, KeyRound, Pencil } from "lucide-react";

import StatusBadge from "@/components/common/StatusBadge";
import { useToast } from "@/components/common/ToastProvider";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import UserFormDialog from "@/components/users/UserFormDialog";
import { api } from "@/lib/api";
import { hasPermission } from "@/lib/permissions";
import type { CurrentUser, Role } from "@/types/rbac";
import type { User, UserPayload } from "@/types/user";

function getErrorMessage(error: unknown) {
  if (typeof error === "object" && error !== null && "response" in error) {
    const response = (error as { response?: { data?: { detail?: string } } }).response;
    return response?.data?.detail ?? "Aktion konnte nicht abgeschlossen werden";
  }

  return "Aktion konnte nicht abgeschlossen werden";
}

function formatDateTime(value: string) {
  return new Intl.DateTimeFormat("de-DE", {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(new Date(value));
}

export default function UserDetailPage() {
  const { showToast } = useToast();
  const params = useParams<{ id: string }>();
  const [user, setUser] = useState<User | null>(null);
  const [roles, setRoles] = useState<Role[]>([]);
  const [currentUser, setCurrentUser] = useState<CurrentUser | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [pending, setPending] = useState(false);
  const [formOpen, setFormOpen] = useState(false);
  const [formError, setFormError] = useState("");
  const [passwordOpen, setPasswordOpen] = useState(false);
  const [password, setPassword] = useState("");
  const [passwordError, setPasswordError] = useState("");

  const loadUser = useCallback(async () => {
    try {
      const [userResponse, meResponse] = await Promise.all([
        api.get<User>(`/users/${params.id}`),
        api.get<CurrentUser>("/me"),
      ]);
      setUser(userResponse.data);
      setCurrentUser(meResponse.data);

      if (hasPermission(meResponse.data, "roles.read")) {
        const rolesResponse = await api.get<Role[]>("/roles");
        setRoles(rolesResponse.data);
      } else {
        setRoles([userResponse.data.primary_role]);
      }
    } catch (err) {
      setError(getErrorMessage(err));
    } finally {
      setLoading(false);
    }
  }, [params.id]);

  useEffect(() => {
    queueMicrotask(() => {
      void loadUser();
    });
  }, [loadUser]);

  async function saveUser(payload: UserPayload) {
    if (!user) {
      return;
    }

    setPending(true);
    setFormError("");

    try {
      const response = await api.put<User>(`/users/${user.id}`, payload);
      setUser(response.data);
      setFormOpen(false);
      showToast({ type: "success", title: "Benutzer aktualisiert", description: response.data.username });
    } catch (err) {
      const message = getErrorMessage(err);
      setFormError(message);
      showToast({ type: "error", title: "Benutzer konnte nicht gespeichert werden", description: message });
    } finally {
      setPending(false);
    }
  }

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

    if (!user || password.length < 8) {
      setPasswordError("Passwort muss mindestens 8 Zeichen lang sein");
      return;
    }

    setPending(true);
    setPasswordError("");

    try {
      const response = await api.put<User>(`/users/${user.id}?action=password`, {
        password,
      });
      setUser(response.data);
      setPassword("");
      setPasswordOpen(false);
      showToast({ type: "success", title: "Passwort geändert", description: response.data.username });
    } catch (err) {
      const message = getErrorMessage(err);
      setPasswordError(message);
      showToast({ type: "error", title: "Passwort konnte nicht geändert werden", description: message });
    } finally {
      setPending(false);
    }
  }

  if (loading) {
    return <div className="rounded-lg border bg-white p-8 text-slate-500">Benutzer wird geladen...</div>;
  }

  if (error || !user) {
    return (
      <div className="space-y-4">
        <Link
          href="/users"
          className="inline-flex h-8 items-center justify-center rounded-lg border border-border bg-background px-2.5 text-sm font-medium hover:bg-muted"
        >
          Zurück
        </Link>
        <div className="rounded-lg border bg-white p-8 text-red-600">
          {error || "Benutzer nicht gefunden"}
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
        <div>
          <Link
            href="/users"
            className="inline-flex items-center gap-2 text-sm text-slate-500 hover:text-slate-900"
          >
            <ArrowLeft size={16} />
            Zurück zur Benutzerliste
          </Link>
          <h1 className="mt-3 text-3xl font-bold text-slate-950">{user.username}</h1>
          <p className="mt-1 text-sm text-slate-500">{user.email}</p>
        </div>

        <div className="flex gap-2">
          {hasPermission(currentUser, "users.password.update") && (
            <Button type="button" variant="outline" onClick={() => setPasswordOpen(true)}>
              <KeyRound size={16} />
              Passwort ändern
            </Button>
          )}
          {hasPermission(currentUser, "users.update") && (
            <Button type="button" onClick={() => setFormOpen(true)}>
              <Pencil size={16} />
              Bearbeiten
            </Button>
          )}
        </div>
      </div>

      <section className="rounded-lg border bg-white p-6">
        <h2 className="text-lg font-semibold">Informationen</h2>
        <dl className="mt-6 grid gap-5 md:grid-cols-2">
          <Detail label="Vorname" value={user.first_name || "-"} />
          <Detail label="Nachname" value={user.last_name || "-"} />
          <Detail label="Benutzername" value={user.username} />
          <Detail label="E-Mail" value={user.email} />
          <Detail label="Rolle" value={user.primary_role.display_name} />
          <div>
            <dt className="text-sm text-slate-500">Status</dt>
            <dd className="mt-1"><StatusBadge active={user.is_active} /></dd>
          </div>
          <Detail label="Erstellt" value={formatDateTime(user.created_at)} />
          <Detail label="Aktualisiert" value={formatDateTime(user.updated_at)} />
        </dl>
      </section>

      <UserFormDialog
        open={formOpen}
        user={user}
        pending={pending}
        serverError={formError}
        roles={roles}
        onOpenChange={setFormOpen}
        onSubmit={saveUser}
      />

      <Dialog open={passwordOpen} onOpenChange={setPasswordOpen}>
        <DialogContent>
          <form onSubmit={savePassword} className="space-y-5">
            <DialogHeader>
              <DialogTitle>Passwort ändern</DialogTitle>
              <DialogDescription>
                Das Passwort wird serverseitig mit pwdlib gehasht.
              </DialogDescription>
            </DialogHeader>

            <div className="space-y-1.5">
              <Label>Neues Passwort</Label>
              <Input
                type="password"
                value={password}
                aria-invalid={Boolean(passwordError)}
                onChange={(event) => setPassword(event.target.value)}
              />
              {passwordError && <p className="text-xs text-red-600">{passwordError}</p>}
            </div>

            <DialogFooter>
              <Button
                type="button"
                variant="outline"
                disabled={pending}
                onClick={() => setPasswordOpen(false)}
              >
                Abbrechen
              </Button>
              <Button type="submit" disabled={pending || password.length < 8}>
                {pending ? "Speichern..." : "Speichern"}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function Detail({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <dt className="text-sm text-slate-500">{label}</dt>
      <dd className="mt-1 font-medium text-slate-950">{value}</dd>
    </div>
  );
}
