"use client";

import React from "react";

import { useAuth } from "@/components/auth/authContext";
import { changePassword, ApiClientError } from "@/lib/frontend/apiClient";
import {
	notifyError,
	notifySuccess,
	notifyApiError,
} from "@/lib/frontend/ui/toast";
import { buildLoginUrl, LOGIN_REASONS } from "@/lib/frontend/authRedirect";
import {
	getPasswordPolicyHintLinesDe,
	reasonsToHintLinesDe,
	buildWeakPasswordMessageDe,
} from "@/lib/frontend/profile/passwordPolicyUi";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
import {
	Card,
	CardHeader,
	CardTitle,
	CardDescription,
	CardContent,
	CardFooter,
} from "@/components/ui/card";

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

export default function ChangePasswordCard({ onPasswordChangeSuccess }) {
	const { status, user, retry } = useAuth();
	const isAuthenticated = status === "authenticated" && user;

	const [currentPassword, setCurrentPassword] = React.useState("");
	const [newPassword, setNewPassword] = React.useState("");
	const [confirmNewPassword, setConfirmNewPassword] = React.useState("");

	const [isSubmitting, setIsSubmitting] = React.useState(false);

	const [error, setError] = React.useState(null);
	// error: { title: string, description?: string|null, field?: string|null, hints?: string[]|null }

	const policyLines = React.useMemo(() => {
		return getPasswordPolicyHintLinesDe();
	}, []);

	function clearForm() {
		setCurrentPassword("");
		setNewPassword("");
		setConfirmNewPassword("");
	}

	function redirectToLoginExpired() {
		const next =
			typeof window !== "undefined"
				? `${window.location.pathname}${window.location.search}`
				: "/profile";

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

	async function onSubmit(e) {
		e.preventDefault();
		if (isSubmitting) return;

		setError(null);

		if (!isAuthenticated) {
			notifyError({
				title: "Nicht angemeldet",
				description: "Bitte melden Sie sich an, um Ihr Passwort zu ändern.",
			});
			return;
		}

		if (!isNonEmptyString(currentPassword)) {
			setError({
				field: "currentPassword",
				title: "Bitte aktuelles Passwort eingeben.",
				description: null,
			});
			return;
		}

		if (!isNonEmptyString(newPassword)) {
			setError({
				field: "newPassword",
				title: "Bitte ein neues Passwort eingeben.",
				description: null,
			});
			return;
		}

		if (!isNonEmptyString(confirmNewPassword)) {
			setError({
				field: "confirmNewPassword",
				title: "Bitte neues Passwort bestätigen.",
				description: null,
			});
			return;
		}

		if (newPassword !== confirmNewPassword) {
			setError({
				field: "confirmNewPassword",
				title: "Passwörter stimmen nicht überein.",
				description: "Bitte prüfen Sie die Bestätigung.",
			});
			return;
		}

		if (newPassword === currentPassword) {
			setError({
				field: "newPassword",
				title: "Neues Passwort ist ungültig.",
				description:
					"Neues Passwort darf nicht identisch zum aktuellen Passwort sein.",
			});
			return;
		}

		setIsSubmitting(true);

		try {
			await changePassword({
				currentPassword,
				newPassword,
			});

			clearForm();

			notifySuccess({
				title: "Passwort geändert",
				description: "Ihr Passwort wurde erfolgreich aktualisiert.",
			});

			if (typeof onPasswordChangeSuccess === "function") {
				onPasswordChangeSuccess();
			}

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

				if (err.code === "AUTH_INVALID_CREDENTIALS") {
					const title = "Aktuelles Passwort ist falsch.";
					setError({ field: "currentPassword", title, description: null });
					notifyError({ title });
					return;
				}

				if (err.code === "VALIDATION_WEAK_PASSWORD") {
					const reasons = err.details?.reasons;
					const minLength = err.details?.minLength;

					const hints = reasonsToHintLinesDe({ reasons, minLength });
					const description = buildWeakPasswordMessageDe({
						reasons,
						minLength,
					});

					setError({
						field: "newPassword",
						title: "Neues Passwort ist zu schwach.",
						description,
						hints,
					});

					notifyError({
						title: "Neues Passwort ist zu schwach.",
						description,
					});
					return;
				}
			}

			setError({
				field: null,
				title: "Passwort konnte nicht geändert werden.",
				description: "Bitte versuchen Sie es erneut.",
			});

			notifyApiError(err, {
				fallbackTitle: "Passwort konnte nicht geändert werden.",
				fallbackDescription: "Bitte versuchen Sie es erneut.",
			});
		} finally {
			setIsSubmitting(false);
		}
	}

	const showError = Boolean(error && error.title);

	return (
		<Card>
			<CardHeader>
				<CardTitle>Passwort</CardTitle>
				<CardDescription>Ändern Sie Ihr Passwort.</CardDescription>
			</CardHeader>

			<CardContent className="space-y-4">
				{!isAuthenticated ? (
					<p className="text-sm text-muted-foreground">
						Hinweis: Passwortänderungen sind nur verfügbar, wenn Sie angemeldet
						sind.
					</p>
				) : null}

				{showError ? (
					<Alert variant="destructive">
						<AlertTitle>{error.title}</AlertTitle>
						{error.description ? (
							<AlertDescription>{error.description}</AlertDescription>
						) : null}

						{Array.isArray(error.hints) && error.hints.length > 0 ? (
							<AlertDescription>
								<ul className="mt-2 list-disc pl-5">
									{error.hints.map((line) => (
										<li key={line}>{line}</li>
									))}
								</ul>
							</AlertDescription>
						) : null}
					</Alert>
				) : null}

				<form onSubmit={onSubmit} className="space-y-4">
					<div className="grid gap-2">
						<Label htmlFor="currentPassword">Aktuelles Passwort</Label>
						<Input
							id="currentPassword"
							type="password"
							autoComplete="current-password"
							value={currentPassword}
							onChange={(e) => setCurrentPassword(e.target.value)}
							disabled={!isAuthenticated || isSubmitting}
							aria-invalid={
								error?.field === "currentPassword" ? "true" : "false"
							}
						/>
					</div>

					<div className="grid gap-2">
						<Label htmlFor="newPassword">Neues Passwort</Label>
						<Input
							id="newPassword"
							type="password"
							autoComplete="new-password"
							value={newPassword}
							onChange={(e) => setNewPassword(e.target.value)}
							disabled={!isAuthenticated || isSubmitting}
							aria-invalid={error?.field === "newPassword" ? "true" : "false"}
						/>

						<ul className="mt-1 list-disc pl-5 text-xs text-muted-foreground">
							{policyLines.map((line) => (
								<li key={line}>{line}</li>
							))}
						</ul>
					</div>

					<div className="grid gap-2">
						<Label htmlFor="confirmNewPassword">
							Neues Passwort bestätigen
						</Label>
						<Input
							id="confirmNewPassword"
							type="password"
							autoComplete="new-password"
							value={confirmNewPassword}
							onChange={(e) => setConfirmNewPassword(e.target.value)}
							disabled={!isAuthenticated || isSubmitting}
							aria-invalid={
								error?.field === "confirmNewPassword" ? "true" : "false"
							}
						/>
					</div>

					<CardFooter className="p-0 flex justify-start">
						<Button
							type="submit"
							disabled={!isAuthenticated || isSubmitting}
							title={!isAuthenticated ? "Bitte anmelden" : "Passwort ändern"}
						>
							{isSubmitting ? "Speichern…" : "Passwort ändern"}
						</Button>
					</CardFooter>
				</form>
			</CardContent>
		</Card>
	);
}
