import FormFooter from "@/components/formFooter";
import { Badge } from "@/components/ui/badge";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import NumberAndSelect from "@/components/ui/numberAndSelect";
import { resetDurationOptions } from "@/lib/constants/governance";
import { getErrorMessage, useCreateCustomerMutation, useUpdateCustomerMutation } from "@/lib/store";
import { CreateCustomerRequest, Customer, UpdateCustomerRequest } from "@/lib/types/governance";
import { formatCurrency } from "@/lib/utils/governance";
import { Validator } from "@/lib/utils/validation";
import { RbacOperation, RbacResource, useRbac } from "@enterprise/lib";
import { formatDistanceToNow } from "date-fns";
import isEqual from "lodash.isequal";
import { useEffect, useMemo, useState } from "react";
import { toast } from "sonner";

interface CustomerDialogProps {
	customer?: Customer | null;
	onSave: () => void;
	onCancel: () => void;
}

interface CustomerFormData {
	name: string;
	// Budget
	budgetMaxLimit: number | undefined;
	budgetResetDuration: string;
	// Rate Limit
	tokenMaxLimit: number | undefined;
	tokenResetDuration: string;
	requestMaxLimit: number | undefined;
	requestResetDuration: string;
	isDirty: boolean;
}

// Helper function to create initial state
const createInitialState = (customer?: Customer | null): Omit<CustomerFormData, "isDirty"> => {
	return {
		name: customer?.name || "",
		// Budget
		budgetMaxLimit: customer?.budget?.max_limit ?? undefined,
		budgetResetDuration: customer?.budget?.reset_duration || "1M",
		// Rate Limit
		tokenMaxLimit: customer?.rate_limit?.token_max_limit ?? undefined,
		tokenResetDuration: customer?.rate_limit?.token_reset_duration || "1h",
		requestMaxLimit: customer?.rate_limit?.request_max_limit ?? undefined,
		requestResetDuration: customer?.rate_limit?.request_reset_duration || "1h",
	};
};

export default function CustomerDialog({ customer, onSave, onCancel }: CustomerDialogProps) {
	const isEditing = !!customer;
	const [initialState] = useState<Omit<CustomerFormData, "isDirty">>(createInitialState(customer));
	const [formData, setFormData] = useState<CustomerFormData>({
		...initialState,
		isDirty: false,
	});

	const hasCreateAccess = useRbac(RbacResource.Customers, RbacOperation.Create);
	const hasUpdateAccess = useRbac(RbacResource.Customers, RbacOperation.Update);
	const hasPermission = isEditing ? hasUpdateAccess : hasCreateAccess;

	// RTK Query hooks
	const [createCustomer, { isLoading: isCreating }] = useCreateCustomerMutation();
	const [updateCustomer, { isLoading: isUpdating }] = useUpdateCustomerMutation();
	const loading = isCreating || isUpdating;

	// Track isDirty state
	useEffect(() => {
		const currentData = {
			name: formData.name,
			budgetMaxLimit: formData.budgetMaxLimit,
			budgetResetDuration: formData.budgetResetDuration,
			tokenMaxLimit: formData.tokenMaxLimit,
			tokenResetDuration: formData.tokenResetDuration,
			requestMaxLimit: formData.requestMaxLimit,
			requestResetDuration: formData.requestResetDuration,
		};
		setFormData((prev) => ({
			...prev,
			isDirty: !isEqual(initialState, currentData),
		}));
	}, [
		formData.name,
		formData.budgetMaxLimit,
		formData.budgetResetDuration,
		formData.tokenMaxLimit,
		formData.tokenResetDuration,
		formData.requestMaxLimit,
		formData.requestResetDuration,
		initialState,
	]);

	// Values for validation and submission (already numbers)
	const budgetMaxLimitNum = formData.budgetMaxLimit;
	const tokenMaxLimitNum = formData.tokenMaxLimit;
	const requestMaxLimitNum = formData.requestMaxLimit;

	// Validation
	const validator = useMemo(
		() =>
			new Validator([
				// Basic validation
				Validator.required(formData.name.trim(), "Customer name is required"),

				// Check if anything is dirty
				Validator.custom(formData.isDirty, "No changes to save"),

				// Budget validation
				...(formData.budgetMaxLimit !== undefined && formData.budgetMaxLimit !== null
					? [
							Validator.minValue(budgetMaxLimitNum ?? 0, 0.01, "Budget max limit must be greater than $0.01"),
							Validator.required(formData.budgetResetDuration, "Budget reset duration is required"),
						]
					: []),

				// Rate limit validation - token limits
				...(formData.tokenMaxLimit !== undefined && formData.tokenMaxLimit !== null
					? [
							Validator.minValue(tokenMaxLimitNum ?? 0, 1, "Token max limit must be at least 1"),
							Validator.required(formData.tokenResetDuration, "Token reset duration is required"),
						]
					: []),

				// Rate limit validation - request limits
				...(formData.requestMaxLimit !== undefined && formData.requestMaxLimit !== null
					? [
							Validator.minValue(requestMaxLimitNum ?? 0, 1, "Request max limit must be at least 1"),
							Validator.required(formData.requestResetDuration, "Request reset duration is required"),
						]
					: []),
			]),
		[formData, budgetMaxLimitNum, tokenMaxLimitNum, requestMaxLimitNum],
	);

	const updateField = <K extends keyof CustomerFormData>(field: K, value: CustomerFormData[K]) => {
		setFormData((prev) => ({ ...prev, [field]: value }));
	};

	const handleSubmit = async (e: React.FormEvent) => {
		e.preventDefault();

		if (!validator.isValid()) {
			toast.error(validator.getFirstError());
			return;
		}

		try {
			if (isEditing && customer) {
				// Update existing customer
				const updateData: UpdateCustomerRequest = {
					name: formData.name,
				};

				// Detect budget changes using had/has pattern
				const hadBudget = !!customer.budget;
				const hasBudget = budgetMaxLimitNum !== undefined && budgetMaxLimitNum !== null;
				if (hasBudget) {
					updateData.budget = {
						max_limit: budgetMaxLimitNum,
						reset_duration: formData.budgetResetDuration,
					};
				} else if (hadBudget) {
					updateData.budget = {} as UpdateCustomerRequest["budget"];
				}

				// Detect rate limit changes using had/has pattern
				const hadRateLimit = !!customer.rate_limit;
				const hasRateLimit =
					(tokenMaxLimitNum !== undefined && tokenMaxLimitNum !== null) ||
					(requestMaxLimitNum !== undefined && requestMaxLimitNum !== null);
				if (hasRateLimit) {
					updateData.rate_limit = {
						token_max_limit: tokenMaxLimitNum,
						token_reset_duration: tokenMaxLimitNum !== undefined && tokenMaxLimitNum !== null ? formData.tokenResetDuration : undefined,
						request_max_limit: requestMaxLimitNum,
						request_reset_duration:
							requestMaxLimitNum !== undefined && requestMaxLimitNum !== null ? formData.requestResetDuration : undefined,
					};
				} else if (hadRateLimit) {
					updateData.rate_limit = {} as UpdateCustomerRequest["rate_limit"];
				}

				await updateCustomer({ customerId: customer.id, data: updateData }).unwrap();
				toast.success("Customer updated successfully");
			} else {
				// Create new customer
				const createData: CreateCustomerRequest = {
					name: formData.name,
				};

				// Add budget if enabled
				if (budgetMaxLimitNum !== undefined && budgetMaxLimitNum !== null) {
					createData.budget = {
						max_limit: budgetMaxLimitNum,
						reset_duration: formData.budgetResetDuration,
					};
				}

				// Add rate limit if enabled (token or request limits)
				if (
					(tokenMaxLimitNum !== undefined && tokenMaxLimitNum !== null) ||
					(requestMaxLimitNum !== undefined && requestMaxLimitNum !== null)
				) {
					createData.rate_limit = {
						token_max_limit: tokenMaxLimitNum,
						token_reset_duration: tokenMaxLimitNum !== undefined && tokenMaxLimitNum !== null ? formData.tokenResetDuration : undefined,
						request_max_limit: requestMaxLimitNum,
						request_reset_duration:
							requestMaxLimitNum !== undefined && requestMaxLimitNum !== null ? formData.requestResetDuration : undefined,
					};
				}

				await createCustomer(createData).unwrap();
				toast.success("Customer created successfully");
			}

			onSave();
		} catch (error) {
			toast.error(getErrorMessage(error));
		}
	};

	return (
		<Dialog open onOpenChange={onCancel}>
			<DialogContent className="max-w-2xl" data-testid="customer-dialog-content">
				<DialogHeader>
					<DialogTitle className="flex items-center gap-2">{isEditing ? "Edit Customer" : "Create Customer"}</DialogTitle>
					<DialogDescription>
						{isEditing
							? "Update the customer information and settings."
							: "Create a new customer account to organize teams and manage resources."}
					</DialogDescription>
				</DialogHeader>

				<form onSubmit={handleSubmit} className="space-y-6">
					<div className="space-y-6">
						{/* Basic Information */}
						<div className="space-y-4">
							<div className="space-y-2">
								<Label htmlFor="name">Customer Name *</Label>
								<Input
									id="name"
									data-testid="customer-name-input"
									placeholder="e.g., Acme Corporation"
									value={formData.name}
									maxLength={50}
									onChange={(e) => updateField("name", e.target.value)}
								/>
								<p className="text-muted-foreground text-sm">This name will be used to identify the customer account.</p>
							</div>
						</div>

						{/* Budget Configuration */}
						<NumberAndSelect
							id="budgetMaxLimit"
							label="Maximum Spend (USD)"
							value={formData.budgetMaxLimit}
							selectValue={formData.budgetResetDuration}
							onChangeNumber={(value) => updateField("budgetMaxLimit", value)}
							onChangeSelect={(value) => updateField("budgetResetDuration", value)}
							options={resetDurationOptions}
							dataTestId="budget-max-limit-input"
						/>

						{/* Rate Limit Configuration - Token Limits */}
						<NumberAndSelect
							id="tokenMaxLimit"
							label="Maximum Tokens"
							value={formData.tokenMaxLimit}
							selectValue={formData.tokenResetDuration}
							onChangeNumber={(value) => updateField("tokenMaxLimit", value)}
							onChangeSelect={(value) => updateField("tokenResetDuration", value)}
							options={resetDurationOptions}
						/>

						{/* Rate Limit Configuration - Request Limits */}
						<NumberAndSelect
							id="requestMaxLimit"
							label="Maximum Requests"
							value={formData.requestMaxLimit}
							selectValue={formData.requestResetDuration}
							onChangeNumber={(value) => updateField("requestMaxLimit", value)}
							onChangeSelect={(value) => updateField("requestResetDuration", value)}
							options={resetDurationOptions}
						/>

						{/* Current Usage Section (only shown when editing with existing limits) */}
						{isEditing && (customer?.budget || customer?.rate_limit) && (
							<div className="bg-muted/50 space-y-4 rounded-lg border p-4">
								<p className="text-sm font-medium">Current Usage</p>
								<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
									{customer?.budget && (
										<div className="space-y-1">
											<p className="text-muted-foreground text-xs">Budget</p>
											<div className="flex items-center gap-2">
												<span className="font-mono text-sm">
													{formatCurrency(customer.budget.current_usage)} / {formatCurrency(customer.budget.max_limit)}
												</span>
												<Badge
													variant={customer.budget.current_usage >= customer.budget.max_limit ? "destructive" : "default"}
													className="text-xs"
												>
													{Math.round((customer.budget.current_usage / customer.budget.max_limit) * 100)}%
												</Badge>
											</div>
											<p className="text-muted-foreground text-xs">
												Last Reset: {formatDistanceToNow(new Date(customer.budget.last_reset), { addSuffix: true })}
											</p>
										</div>
									)}
									{customer?.rate_limit?.token_max_limit && (
										<div className="space-y-1">
											<p className="text-muted-foreground text-xs">Tokens</p>
											<div className="flex items-center gap-2">
												<span className="font-mono text-sm">
													{customer.rate_limit.token_current_usage.toLocaleString()} /{" "}
													{customer.rate_limit.token_max_limit.toLocaleString()}
												</span>
												<Badge
													variant={
														customer.rate_limit.token_current_usage >= customer.rate_limit.token_max_limit ? "destructive" : "default"
													}
													className="text-xs"
												>
													{Math.round((customer.rate_limit.token_current_usage / customer.rate_limit.token_max_limit) * 100)}%
												</Badge>
											</div>
											<p className="text-muted-foreground text-xs">
												Last Reset: {formatDistanceToNow(new Date(customer.rate_limit.token_last_reset), { addSuffix: true })}
											</p>
										</div>
									)}
									{customer?.rate_limit?.request_max_limit && (
										<div className="space-y-1">
											<p className="text-muted-foreground text-xs">Requests</p>
											<div className="flex items-center gap-2">
												<span className="font-mono text-sm">
													{customer.rate_limit.request_current_usage.toLocaleString()} /{" "}
													{customer.rate_limit.request_max_limit.toLocaleString()}
												</span>
												<Badge
													variant={
														customer.rate_limit.request_current_usage >= customer.rate_limit.request_max_limit ? "destructive" : "default"
													}
													className="text-xs"
												>
													{Math.round((customer.rate_limit.request_current_usage / customer.rate_limit.request_max_limit) * 100)}%
												</Badge>
											</div>
											<p className="text-muted-foreground text-xs">
												Last Reset: {formatDistanceToNow(new Date(customer.rate_limit.request_last_reset), { addSuffix: true })}
											</p>
										</div>
									)}
								</div>
							</div>
						)}
					</div>

					<FormFooter
						validator={validator}
						label="Customer"
						onCancel={onCancel}
						isLoading={loading}
						isEditing={isEditing}
						hasPermission={hasPermission}
					/>
				</form>
			</DialogContent>
		</Dialog>
	);
}