import React, { useState } from "react";
import { Button } from "../button";
import { Card, CardContent, CardHeader, CardTitle } from "../card";
import { cn } from "@repo/ui/lib/utils";

// Base interface for form fields
export interface FormField {
	key: string;
	label: string;
	type:
		| "text"
		| "number"
		| "email"
		| "password"
		| "textarea"
		| "url"
		| "tel"
		| "date"
		| "select"
		| "checkbox";
	required?: boolean;
	placeholder?: string;
	options?: { value: string; label: string }[]; // For select fields
	validation?: {
		min?: number;
		max?: number;
		pattern?: string;
		minLength?: number;
		maxLength?: number;
	};
	className?: string;
	disabled?: boolean;
	helpText?: string;
}

// Generic form data interface
export interface FormData {
	[key: string]: string | number | boolean;
}

interface CreateFormProps {
	title: string;
	fields: FormField[];
	onSubmit: (data: FormData) => Promise<void>;
	onCancel?: () => void;
	loading?: boolean;
	submitText?: string;
	cancelText?: string;
	className?: string;
	initialData?: FormData;
}

export function CreateForm({
	title,
	fields,
	onSubmit,
	onCancel,
	loading = false,
	submitText = "Create",
	cancelText = "Cancel",
	className,
	initialData = {},
}: CreateFormProps) {
	const [formData, setFormData] = useState<FormData>(() => {
		const initial: FormData = {};
		fields.forEach((field) => {
			initial[field.key] =
				initialData[field.key] ||
				(field.type === "number"
					? 0
					: field.type === "checkbox"
						? false
						: "");
		});
		return initial;
	});

	const [errors, setErrors] = useState<Record<string, string>>({});
	const [isSubmitting, setIsSubmitting] = useState(false);

	const validateField = (
		field: FormField,
		value: string | number | boolean
	): string | null => {
		if (
			field.required &&
			(!value || (typeof value === "string" && !value.trim()))
		) {
			return `${field.label} is required`;
		}

		if (field.validation) {
			const { min, max, pattern, minLength, maxLength } =
				field.validation;

			if (field.type === "number" && typeof value === "number") {
				if (min !== undefined && value < min) {
					return `${field.label} must be at least ${min}`;
				}
				if (max !== undefined && value > max) {
					return `${field.label} must be at most ${max}`;
				}
			}

			if (typeof value === "string") {
				if (minLength !== undefined && value.length < minLength) {
					return `${field.label} must be at least ${minLength} characters`;
				}
				if (maxLength !== undefined && value.length > maxLength) {
					return `${field.label} must be at most ${maxLength} characters`;
				}
				if (pattern && !new RegExp(pattern).test(value)) {
					return `${field.label} format is invalid`;
				}
			}
		}

		return null;
	};

	const validateForm = (): boolean => {
		const newErrors: Record<string, string> = {};

		fields.forEach((field) => {
			const error = validateField(field, formData[field.key]);
			if (error) {
				newErrors[field.key] = error;
			}
		});

		setErrors(newErrors);
		return Object.keys(newErrors).length === 0;
	};

	const handleInputChange = (
		key: string,
		value: string | number | boolean
	) => {
		setFormData((prev) => ({ ...prev, [key]: value }));

		// Clear error when user starts typing
		if (errors[key]) {
			setErrors((prev) => ({ ...prev, [key]: "" }));
		}
	};

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

		if (!validateForm()) {
			return;
		}

		setIsSubmitting(true);
		try {
			await onSubmit(formData);

			// Reset form on success
			const resetData: FormData = {};
			fields.forEach((field) => {
				resetData[field.key] =
					field.type === "number"
						? 0
						: field.type === "checkbox"
							? false
							: "";
			});
			setFormData(resetData);
			setErrors({});
		} catch (error: unknown) {
			setErrors({
				submit:
					error instanceof Error
						? error.message
						: "An error occurred",
			});
		} finally {
			setIsSubmitting(false);
		}
	};

	const renderField = (field: FormField) => {
		const isFieldDisabled = loading || isSubmitting || field.disabled;
		const fieldError = errors[field.key];

		const baseInputClasses = cn(
			"w-full mt-1 p-2 border rounded-md transition-colors",
			"focus:ring-2 focus:ring-blue-500 focus:border-transparent",
			fieldError ? "border-red-500" : "border-gray-300",
			isFieldDisabled && "opacity-50 cursor-not-allowed",
			field.className
		);

		switch (field.type) {
			case "textarea":
				return (
					<textarea
						className={baseInputClasses}
						value={formData[field.key] || ""}
						onChange={(e) =>
							handleInputChange(field.key, e.target.value)
						}
						disabled={isFieldDisabled}
						placeholder={field.placeholder}
						rows={3}
					/>
				);

			case "select":
				return (
					<select
						className={baseInputClasses}
						value={formData[field.key] || ""}
						onChange={(e) =>
							handleInputChange(field.key, e.target.value)
						}
						disabled={isFieldDisabled}
					>
						<option value="">
							{field.placeholder || `Select ${field.label}`}
						</option>
						{field.options?.map((option) => (
							<option key={option.value} value={option.value}>
								{option.label}
							</option>
						))}
					</select>
				);

			case "checkbox":
				return (
					<div className="flex items-center">
						<input
							type="checkbox"
							className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
							checked={formData[field.key] || false}
							onChange={(e) =>
								handleInputChange(field.key, e.target.checked)
							}
							disabled={isFieldDisabled}
						/>
						<label className="ml-2 text-sm text-gray-700">
							{field.placeholder || field.label}
						</label>
					</div>
				);

			case "number":
				return (
					<input
						type="number"
						className={baseInputClasses}
						value={formData[field.key] || ""}
						onChange={(e) =>
							handleInputChange(
								field.key,
								parseFloat(e.target.value) || 0
							)
						}
						disabled={isFieldDisabled}
						placeholder={field.placeholder}
						min={field.validation?.min}
						max={field.validation?.max}
						step={field.type === "number" ? "any" : undefined}
					/>
				);

			default:
				return (
					<input
						type={field.type}
						className={baseInputClasses}
						value={formData[field.key] || ""}
						onChange={(e) =>
							handleInputChange(field.key, e.target.value)
						}
						disabled={isFieldDisabled}
						placeholder={field.placeholder}
						pattern={field.validation?.pattern}
						minLength={field.validation?.minLength}
						maxLength={field.validation?.maxLength}
					/>
				);
		}
	};

	return (
		<Card className={className}>
			<CardHeader>
				<CardTitle>{title}</CardTitle>
			</CardHeader>
			<CardContent>
				<form onSubmit={handleSubmit} className="space-y-4">
					{fields.map((field) => (
						<div key={field.key}>
							{field.type !== "checkbox" && (
								<label className="block text-sm font-medium text-gray-700">
									{field.label}
									{field.required && (
										<span className="text-red-500 ml-1">
											*
										</span>
									)}
								</label>
							)}

							{renderField(field)}

							{errors[field.key] && (
								<p className="mt-1 text-sm text-red-600">
									{errors[field.key]}
								</p>
							)}

							{field.helpText && (
								<p className="mt-1 text-sm text-gray-500">
									{field.helpText}
								</p>
							)}
						</div>
					))}

					{errors.submit && (
						<div className="text-red-600 text-sm p-2 bg-red-50 rounded">
							{errors.submit}
						</div>
					)}

					<div className="flex gap-2 pt-4">
						{onCancel && (
							<Button
								type="button"
								variant="outline"
								onClick={onCancel}
								disabled={isSubmitting}
								className="flex-1"
							>
								{cancelText}
							</Button>
						)}
						<Button
							type="submit"
							disabled={isSubmitting}
							className="flex-1"
						>
							{isSubmitting ? "Saving..." : submitText}
						</Button>
					</div>
				</form>
			</CardContent>
		</Card>
	);
}

export type { CreateFormProps };
