"use client";

import React from "react";

import { adminUpdateUser, ApiClientError } from "@/lib/frontend/apiClient";
import { buildLoginUrl, LOGIN_REASONS } from "@/lib/frontend/authRedirect";
import { useSearchBranches } from "@/lib/frontend/search/useSearchBranches";
import {
	evaluateBranchExistence,
	isValidBranchIdFormat,
	normalizeBranchIdInput,
} from "@/lib/frontend/admin/users/userManagementUx";
import {
	notifySuccess,
	notifyError,
	notifyApiError,
	notifyInfo,
} from "@/lib/frontend/ui/toast";

import {
	EDIT_ROLE_OPTIONS,
	EMAIL_RE,
	normalizeUsername,
	normalizeEmail,
} from "@/components/admin/users/edit-user/editUserUtils";

function isNonEmptyString(value) {
	return typeof value === "string" && value.trim().length > 0;
}

function buildInitialFormFromUser(user) {
	return {
		username: typeof user?.username === "string" ? user.username : "",
		email: typeof user?.email === "string" ? user.email : "",
		role: typeof user?.role === "string" ? user.role : "branch",
		branchId: typeof user?.branchId === "string" ? user.branchId : "",
		mustChangePassword: Boolean(user?.mustChangePassword),
	};
}

function validateClient(form) {
	const username = normalizeUsername(form?.username);
	const email = normalizeEmail(form?.email);
	const role = String(form?.role || "").trim();

	const isKnownRole = EDIT_ROLE_OPTIONS.some((x) => x.value === role);

	const branchId =
		role === "branch" ? normalizeBranchIdInput(form?.branchId || "") : "";

	if (!username) return { title: "Benutzername fehlt.", description: null };
	if (!email) return { title: "E-Mail fehlt.", description: null };

	if (!EMAIL_RE.test(email)) {
		return {
			title: "E-Mail ist ungültig.",
			description: "Bitte prüfen Sie die Eingabe.",
		};
	}

	if (!role || !isKnownRole) {
		return { title: "Rolle fehlt.", description: null };
	}

	if (role === "branch") {
		if (!branchId) {
			return {
				title: "Niederlassung fehlt.",
				description: "Für Niederlassungs-User ist eine NL erforderlich.",
			};
		}
		if (!isValidBranchIdFormat(branchId)) {
			return {
				title: "Niederlassung ist ungültig.",
				description: "Format: NL01, NL02, ...",
			};
		}
	}

	return null;
}

function extractDuplicateField(details) {
	if (!details || typeof details !== "object") return null;
	if (typeof details.field === "string" && details.field.trim()) {
		return details.field.trim();
	}
	return null;
}

function mapDuplicateFieldToGermanMessage(field) {
	if (field === "username") {
		return {
			title: "Benutzername existiert bereits.",
			description: "Bitte wählen Sie einen anderen Benutzernamen.",
		};
	}
	if (field === "email") {
		return {
			title: "E-Mail existiert bereits.",
			description: "Bitte wählen Sie eine andere E-Mail-Adresse.",
		};
	}
	return null;
}

function buildNormalizedForm(form) {
	const role = String(form?.role || "").trim();

	return {
		username: normalizeUsername(form?.username),
		email: normalizeEmail(form?.email),
		role,
		branchId:
			role === "branch" ? normalizeBranchIdInput(form?.branchId || "") : "",
		mustChangePassword: Boolean(form?.mustChangePassword),
	};
}

function buildPatch({ user, form }) {
	const initial = buildNormalizedForm(buildInitialFormFromUser(user));
	const current = buildNormalizedForm(form);

	const patch = {};

	if (current.username && current.username !== initial.username) {
		patch.username = current.username;
	}

	if (current.email && current.email !== initial.email) {
		patch.email = current.email;
	}

	if (current.role && current.role !== initial.role) {
		patch.role = current.role;
	}

	// branchId handling:
	// - Only meaningful for role=branch
	// - If role becomes non-branch, backend will clear branchId automatically.
	if (current.role === "branch") {
		// If role is branch (either unchanged or changed), enforce branchId in patch when different
		if (current.branchId !== initial.branchId) {
			patch.branchId = current.branchId;
		}
	} else {
		// If user was branch before and we did not change role explicitly (rare),
		// we do not auto-clear here. Backend will enforce consistency based on role updates.
	}

	if (current.mustChangePassword !== initial.mustChangePassword) {
		patch.mustChangePassword = current.mustChangePassword;
	}

	return patch;
}

export function useEditUserDialog({ user, disabled = false, onUpdated } = {}) {
	const [open, setOpen] = React.useState(false);
	const [isSubmitting, setIsSubmitting] = React.useState(false);

	const [form, setForm] = React.useState(() => buildInitialFormFromUser(user));
	const [error, setError] = React.useState(null);

	const role = String(form?.role || "branch").trim();
	const shouldLoadBranches = open && role === "branch";
	const { status: branchesStatus, branches: availableBranchIds } =
		useSearchBranches({ enabled: shouldLoadBranches });

	const effectiveDisabled = Boolean(disabled || isSubmitting || !user?.id);
	const branchExistence = React.useMemo(
		() =>
			evaluateBranchExistence({
				role,
				branchId: form?.branchId,
				branchesStatus,
				availableBranchIds,
			}),
		[role, form?.branchId, branchesStatus, availableBranchIds],
	);

	const patchPreview = React.useMemo(() => {
		return buildPatch({ user, form });
	}, [
		user?.id,
		user?.username,
		user?.email,
		user?.role,
		user?.branchId,
		user?.mustChangePassword,
		form?.username,
		form?.email,
		form?.role,
		form?.branchId,
		form?.mustChangePassword,
	]);

	const canSubmit = React.useMemo(() => {
		return (
			!effectiveDisabled &&
			Object.keys(patchPreview).length > 0 &&
			!branchExistence.shouldBlockSubmit
		);
	}, [effectiveDisabled, patchPreview, branchExistence.shouldBlockSubmit]);

	const setPatch = React.useCallback((patch) => {
		setForm((prev) => ({ ...prev, ...(patch || {}) }));
	}, []);

	const resetForm = React.useCallback(() => {
		setForm(buildInitialFormFromUser(user));
		setError(null);
	}, [user]);

	const redirectToLoginExpired = React.useCallback(() => {
		const next =
			typeof window !== "undefined"
				? `${window.location.pathname}${window.location.search}`
				: "/admin/users";

		window.location.replace(
			buildLoginUrl({ reason: LOGIN_REASONS.EXPIRED, next }),
		);
	}, []);

	const handleOpenChange = React.useCallback(
		(nextOpen) => {
			setOpen(nextOpen);

			// On open -> initialize from current user snapshot.
			// On close -> clear error and reset form so reopening is always clean.
			if (nextOpen) {
				setForm(buildInitialFormFromUser(user));
				setError(null);
			} else {
				resetForm();
			}
		},
		[user, resetForm],
	);

	const handleSubmit = React.useCallback(
		async (e) => {
			e?.preventDefault?.();
			if (effectiveDisabled) return;

			setError(null);

			const clientErr = validateClient(form);
			if (clientErr) {
				setError(clientErr);
				notifyError({
					title: clientErr.title,
					description: clientErr.description,
				});
				return;
			}

			if (branchExistence.shouldBlockSubmit) {
				const mapped = {
					title: "Niederlassung existiert nicht.",
					description:
						"Die gewählte Niederlassung ist nicht in der aktuellen Liste vorhanden.",
				};
				setError(mapped);
				notifyError(mapped);
				return;
			}

			const patch = buildPatch({ user, form });

			if (Object.keys(patch).length === 0) {
				notifyInfo({
					title: "Keine Änderungen",
					description: "Es wurden keine Felder geändert.",
				});
				setOpen(false);
				resetForm();
				return;
			}

			setIsSubmitting(true);

			try {
				await adminUpdateUser(String(user.id), patch);

				notifySuccess({
					title: "Benutzer aktualisiert",
					description: `Benutzer "${normalizeUsername(form.username)}" wurde gespeichert.`,
				});

				setOpen(false);
				resetForm();

				if (typeof onUpdated === "function") onUpdated();
			} catch (err) {
				if (err instanceof ApiClientError) {
					if (err.code === "AUTH_UNAUTHENTICATED") {
						notifyApiError(err);
						redirectToLoginExpired();
						return;
					}

					if (err.code === "USER_NOT_FOUND") {
						const mapped = {
							title: "Benutzer nicht gefunden.",
							description:
								"Der Benutzer existiert nicht (mehr). Bitte aktualisieren Sie die Liste.",
						};
						setError(mapped);
						notifyError(mapped);
						return;
					}

					if (err.code === "VALIDATION_MISSING_FIELD") {
						const fields = err.details?.fields;
						if (Array.isArray(fields) && fields.includes("branchId")) {
							const mapped = {
								title: "Niederlassung fehlt.",
								description:
									"Für Niederlassungs-User ist eine Niederlassung erforderlich.",
							};
							setError(mapped);
							notifyError(mapped);
							return;
						}
					}

					if (err.code === "VALIDATION_INVALID_FIELD") {
						const field = extractDuplicateField(err.details);
						const mapped = mapDuplicateFieldToGermanMessage(field);

						if (mapped) {
							setError(mapped);
							notifyError(mapped);
							return;
						}
					}

					setError({
						title: "Benutzer konnte nicht aktualisiert werden.",
						description:
							"Bitte prüfen Sie die Eingaben und versuchen Sie es erneut.",
					});

					notifyApiError(err, {
						fallbackTitle: "Benutzer konnte nicht aktualisiert werden.",
						fallbackDescription:
							"Bitte prüfen Sie die Eingaben und versuchen Sie es erneut.",
					});
					return;
				}

				setError({
					title: "Benutzer konnte nicht aktualisiert werden.",
					description: "Bitte versuchen Sie es erneut.",
				});

				notifyError({
					title: "Benutzer konnte nicht aktualisiert werden.",
					description: "Bitte versuchen Sie es erneut.",
				});
			} finally {
				setIsSubmitting(false);
			}
		},
		[
			effectiveDisabled,
			form,
			user,
			onUpdated,
			redirectToLoginExpired,
			resetForm,
			branchExistence.shouldBlockSubmit,
		],
	);

	return {
		open,
		handleOpenChange,
		form,
		setPatch,
		error,
		branchesStatus,
		branchExistence,
		isSubmitting,
		effectiveDisabled,
		canSubmit,
		handleSubmit,
	};
}
