"use client";

import type { SVGProps } from "react";
import React, { type ReactNode, useEffect, useMemo, useState } from "react";
import { cx } from "../lib/utils";
import { OnboardingButton } from "../primitives/onboarding-button";
import { OnboardingCard } from "../primitives/onboarding-card";
import { OnboardingInput } from "../primitives/onboarding-input";
import { OnboardingLabel } from "../primitives/onboarding-label";
import {
	OnboardingRadioCardGroup,
	OnboardingRadioCardItem,
} from "../primitives/onboarding-radio-card";
import {
	OnboardingRadioGroup,
	OnboardingRadioGroupItem,
} from "../primitives/onboarding-radio-group";
import {
	OnboardingSelect,
	OnboardingSelectContent,
	OnboardingSelectItem,
	OnboardingSelectTrigger,
	OnboardingSelectValue,
} from "../primitives/onboarding-select";
import { OnboardingSlider } from "../primitives/onboarding-slider";

export interface Region {
	value: string;
	label: string;
	multiplier: number;
}

export interface CloudProvider {
	id: string;
	name: string;
	icon?: ReactNode;
	regions: Region[];
	basePrice: number;
}

export interface InfrastructureConfig {
	cloudProvider: string;
	region: string;
	storageVolume: number;
	compression: boolean;
	activeHours: number;
}

export interface InfrastructureStepProps {
	/** Title displayed at the top of the step */
	title?: string;
	/** Description text below the title */
	description?: string;
	/** Array of cloud providers to choose from */
	cloudProviders: CloudProvider[];
	/** Initial configuration values */
	defaultConfig?: Partial<InfrastructureConfig>;
	/** Storage volume limits */
	storageLimits?: { min: number; max: number };
	/** Called when configuration changes */
	onConfigChange?: (config: InfrastructureConfig) => void;
	/** Called when the user submits the form */
	onSubmit: (config: InfrastructureConfig) => void | Promise<void>;
	/** Custom price calculator - receives config and returns formatted string */
	calculatePrice?: (
		config: InfrastructureConfig,
		provider: CloudProvider,
	) => string;
	/** Text for the submit button */
	submitText?: string;
	/** Text shown while submitting */
	loadingText?: string;
	/** Optional back button config */
	backButton?: {
		text: string;
		onClick: () => void;
	};
}

// Default icons
const MicrosoftAzure = (props: SVGProps<SVGSVGElement>) => (
	<svg
		viewBox="0 0 96 96"
		xmlns="http://www.w3.org/2000/svg"
		width="1em"
		height="1em"
		{...props}
	>
		<defs>
			<linearGradient
				id="azure-a"
				x1={-1032.17}
				x2={-1059.21}
				y1={145.31}
				y2={65.43}
				gradientTransform="matrix(1 0 0 -1 1075 158)"
				gradientUnits="userSpaceOnUse"
			>
				<stop offset={0} stopColor="#114a8b" />
				<stop offset={1} stopColor="#0669bc" />
			</linearGradient>
			<linearGradient
				id="azure-b"
				x1={-1023.73}
				x2={-1029.98}
				y1={108.08}
				y2={105.97}
				gradientTransform="matrix(1 0 0 -1 1075 158)"
				gradientUnits="userSpaceOnUse"
			>
				<stop offset={0} stopOpacity={0.3} />
				<stop offset={0.07} stopOpacity={0.2} />
				<stop offset={0.32} stopOpacity={0.1} />
				<stop offset={0.62} stopOpacity={0.05} />
				<stop offset={1} stopOpacity={0} />
			</linearGradient>
			<linearGradient
				id="azure-c"
				x1={-1027.16}
				x2={-997.48}
				y1={147.64}
				y2={68.56}
				gradientTransform="matrix(1 0 0 -1 1075 158)"
				gradientUnits="userSpaceOnUse"
			>
				<stop offset={0} stopColor="#3ccbf4" />
				<stop offset={1} stopColor="#2892df" />
			</linearGradient>
		</defs>
		<path
			fill="url(#azure-a)"
			d="M33.34 6.54h26.04l-27.03 80.1a4.15 4.15 0 0 1-3.94 2.81H8.15a4.14 4.14 0 0 1-3.93-5.47L29.4 9.38a4.15 4.15 0 0 1 3.94-2.83z"
		/>
		<path
			fill="#0078d4"
			d="M71.17 60.26H29.88a1.91 1.91 0 0 0-1.3 3.31l26.53 24.76a4.17 4.17 0 0 0 2.85 1.13h23.38z"
		/>
		<path
			fill="url(#azure-b)"
			d="M33.34 6.54a4.12 4.12 0 0 0-3.95 2.88L4.25 83.92a4.14 4.14 0 0 0 3.91 5.54h20.79a4.44 4.44 0 0 0 3.4-2.9l5.02-14.78 17.91 16.7a4.24 4.24 0 0 0 2.67.97h23.29L71.02 60.26H41.24L59.47 6.55z"
		/>
		<path
			fill="url(#azure-c)"
			d="M66.6 9.36a4.14 4.14 0 0 0-3.93-2.82H33.65a4.15 4.15 0 0 1 3.93 2.82l25.18 74.62a4.15 4.15 0 0 1-3.93 5.48h29.02a4.15 4.15 0 0 0 3.93-5.48z"
		/>
	</svg>
);

const AmazonWebServices = (props: SVGProps<SVGSVGElement>) => (
	<svg
		xmlns="http://www.w3.org/2000/svg"
		viewBox="0 0 304 182"
		width="1em"
		height="1em"
		{...props}
	>
		<path
			className="fill-[#252f3e] dark:fill-foreground"
			d="m86 66 2 9c0 3 1 5 3 8v2l-1 3-7 4-2 1-3-1-4-5-3-6c-8 9-18 14-29 14-9 0-16-3-20-8-5-4-8-11-8-19s3-15 9-20c6-6 14-8 25-8a79 79 0 0 1 22 3v-7c0-8-2-13-5-16-3-4-8-5-16-5l-11 1a80 80 0 0 0-14 5h-2c-1 0-2-1-2-3v-5l1-3c0-1 1-2 3-2l12-5 16-2c12 0 20 3 26 8 5 6 8 14 8 25v32zM46 82l10-2c4-1 7-4 10-7l3-6 1-9v-4a84 84 0 0 0-19-2c-6 0-11 1-15 4-3 2-4 6-4 11s1 8 3 11c3 2 6 4 11 4zm80 10-4-1-2-3-23-78-1-4 2-2h10l4 1 2 4 17 66 15-66 2-4 4-1h8l4 1 2 4 16 67 17-67 2-4 4-1h9c2 0 3 1 3 2v2l-1 2-24 78-2 4-4 1h-9l-4-1-1-4-16-65-15 64-2 4-4 1h-9zm129 3a66 66 0 0 1-27-6l-3-3-1-2v-5c0-2 1-3 2-3h2l3 1a54 54 0 0 0 23 5c6 0 11-2 14-4 4-2 5-5 5-9l-2-7-10-5-15-5c-7-2-13-6-16-10a24 24 0 0 1 5-34l10-5a44 44 0 0 1 20-2 110 110 0 0 1 12 3l4 2 3 2 1 4v4c0 3-1 4-2 4l-4-2c-6-2-12-3-19-3-6 0-11 0-14 2s-4 5-4 9c0 3 1 5 3 7s5 4 11 6l14 4c7 3 12 6 15 10s5 9 5 14l-3 12-7 8c-3 3-7 5-11 6l-14 2z"
		/>
		<path
			className="fill-[#f90]"
			d="M274 144A220 220 0 0 1 4 124c-4-3-1-6 2-4a300 300 0 0 0 263 16c5-2 10 4 5 8z"
		/>
		<path
			className="fill-[#f90]"
			d="M287 128c-4-5-28-3-38-1-4 0-4-3-1-5 19-13 50-9 53-5 4 5-1 36-18 51-3 2-6 1-5-2 5-10 13-33 9-38z"
		/>
	</svg>
);

export const defaultCloudProviderIcons: Record<
	string,
	React.ComponentType<SVGProps<SVGSVGElement>>
> = {
	aws: AmazonWebServices,
	azure: MicrosoftAzure,
};

function defaultPriceCalculator(
	config: InfrastructureConfig,
	provider: CloudProvider,
): string {
	const activeHourMultiplier = 0.05;
	const compressionMultiplier = config.compression ? 0.7 : 1.0;

	const selectedRegion = provider.regions.find(
		(r) => r.value === config.region,
	);
	const regionMultiplier = selectedRegion?.multiplier || 1.0;
	const storagePrice =
		provider.basePrice *
		config.storageVolume *
		regionMultiplier *
		compressionMultiplier;
	const activeHoursPrice = config.activeHours * activeHourMultiplier;

	const totalPricePerDay = storagePrice + activeHoursPrice;
	const totalPricePerMonth = totalPricePerDay * 30;

	const priceRangeLow = (totalPricePerMonth * 0.8 * 10).toFixed(0);
	const priceRangeHigh = (totalPricePerMonth * 1.2 * 10).toFixed(0);

	return `${priceRangeLow} - ${priceRangeHigh} USD`;
}

export function InfrastructureStep({
	title = "Create a new compute cluster",
	description = "You have full control over the resources provisioned.",
	cloudProviders,
	defaultConfig,
	storageLimits = { min: 6, max: 128 },
	onConfigChange,
	onSubmit,
	calculatePrice = defaultPriceCalculator,
	submitText = "Continue",
	loadingText = "Submitting...",
	backButton,
}: InfrastructureStepProps) {
	const [cloudProvider, setCloudProvider] = useState(
		defaultConfig?.cloudProvider || cloudProviders[0]?.id || "",
	);
	const [region, setRegion] = useState(defaultConfig?.region || "");
	const [activeHours, setActiveHours] = useState([
		defaultConfig?.activeHours ?? 6,
	]);
	const [storageVolume, setStorageVolume] = useState(
		defaultConfig?.storageVolume ?? storageLimits.min,
	);
	const [compression, setCompression] = useState(
		defaultConfig?.compression ? "true" : "false",
	);
	const [loading, setLoading] = useState(false);

	const currentProvider = useMemo(
		() => cloudProviders.find((p) => p.id === cloudProvider),
		[cloudProviders, cloudProvider],
	);

	useEffect(() => {
		if (currentProvider && currentProvider.regions.length > 0) {
			setRegion(currentProvider.regions[0].value);
		}
	}, [currentProvider]);

	const config: InfrastructureConfig = useMemo(
		() => ({
			cloudProvider,
			region,
			storageVolume,
			compression: compression === "true",
			activeHours: activeHours[0],
		}),
		[cloudProvider, region, storageVolume, compression, activeHours],
	);

	useEffect(() => {
		onConfigChange?.(config);
	}, [config, onConfigChange]);

	const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		setLoading(true);
		try {
			await onSubmit(config);
		} finally {
			setLoading(false);
		}
	};

	const price = currentProvider ? calculatePrice(config, currentProvider) : "";

	const isValid =
		cloudProvider &&
		region &&
		activeHours[0] !== undefined &&
		storageVolume &&
		compression;

	return (
		<main className="mx-auto p-4">
			<div
				style={{ animationDuration: "500ms" }}
				className="motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4"
			>
				<h1 className="text-2xl font-semibold text-foreground sm:text-xl">
					{title}
				</h1>
				<p className="mt-6 text-muted-foreground sm:text-sm">{description}</p>
			</div>

			<form onSubmit={handleSubmit} className="mt-8">
				<div className="flex flex-col gap-6">
					<fieldset
						className="space-y-2 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4"
						style={{
							animationDuration: "500ms",
							animationDelay: "200ms",
							animationFillMode: "backwards",
						}}
					>
						<legend className="font-medium text-foreground sm:text-sm">
							Cloud provider
						</legend>
						<OnboardingRadioCardGroup
							id="cloud-provider"
							value={cloudProvider}
							onValueChange={setCloudProvider}
							className="mt-2 grid grid-cols-1 gap-4 sm:text-sm md:grid-cols-2"
							aria-label="Select cloud provider"
						>
							{cloudProviders.map((provider) => {
								const Icon =
									provider.icon || defaultCloudProviderIcons[provider.id];
								return (
									<OnboardingRadioCardItem
										key={provider.id}
										value={provider.id}
									>
										<div>
											<div className="flex items-center gap-2">
												{Icon &&
													(typeof Icon === "function" ? (
														<Icon
															className="size-5 shrink-0"
															aria-hidden="true"
														/>
													) : (
														Icon
													))}
												<span className="font-semibold leading-6">
													{provider.name}
												</span>
											</div>
											<p className="mt-1 text-sm text-muted-foreground sm:text-xs">
												{provider.regions.length} regions available
											</p>
										</div>
									</OnboardingRadioCardItem>
								);
							})}
						</OnboardingRadioCardGroup>
					</fieldset>

					<div
						className="flex flex-col items-start gap-8 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4 sm:flex-row"
						style={{
							animationDuration: "500ms",
							animationDelay: "400ms",
							animationFillMode: "backwards",
						}}
					>
						<div className="space-y-2">
							<OnboardingLabel
								className="whitespace-nowrap text-base font-medium text-foreground sm:text-sm/7"
								htmlFor="storage"
							>
								Storage (GB)
							</OnboardingLabel>
							<OnboardingInput
								id="storage"
								type="number"
								min={storageLimits.min}
								max={storageLimits.max}
								value={storageVolume}
								onChange={(e) => setStorageVolume(Number(e.target.value))}
								aria-describedby="storage-description"
							/>
							<p id="storage-description" className="sr-only">
								Enter storage volume between {storageLimits.min} and{" "}
								{storageLimits.max} GB
							</p>
						</div>
						<fieldset className="space-y-2">
							<legend className="block font-medium text-foreground sm:text-sm/7">
								Would you like to auto compress your data?
							</legend>
							<OnboardingRadioGroup
								value={compression}
								onValueChange={setCompression}
								className="flex gap-6 pt-2.5"
							>
								<div className="flex items-center gap-x-3">
									<OnboardingRadioGroupItem value="true" id="compression-yes" />
									<OnboardingLabel htmlFor="compression-yes">
										Yes
									</OnboardingLabel>
								</div>
								<div className="flex items-center gap-x-3">
									<OnboardingRadioGroupItem value="false" id="compression-no" />
									<OnboardingLabel htmlFor="compression-no">No</OnboardingLabel>
								</div>
							</OnboardingRadioGroup>
						</fieldset>
					</div>

					<div
						className="space-y-2 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4"
						style={{
							animationDuration: "500ms",
							animationDelay: "600ms",
							animationFillMode: "backwards",
						}}
					>
						<OnboardingLabel
							className="text-base font-medium text-foreground sm:text-sm"
							htmlFor="region"
						>
							Region
						</OnboardingLabel>
						<OnboardingSelect value={region} onValueChange={setRegion}>
							<OnboardingSelectTrigger id="region" className="w-full">
								<OnboardingSelectValue placeholder="Select region" />
							</OnboardingSelectTrigger>
							<OnboardingSelectContent>
								{currentProvider?.regions.map((option) => (
									<OnboardingSelectItem key={option.value} value={option.value}>
										<span className="flex items-center gap-x-2">
											{option.label}
										</span>
									</OnboardingSelectItem>
								))}
							</OnboardingSelectContent>
						</OnboardingSelect>
					</div>

					<div
						className="space-y-2 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4"
						style={{
							animationDuration: "500ms",
							animationDelay: "800ms",
							animationFillMode: "backwards",
						}}
					>
						<OnboardingLabel
							className="text-base font-medium text-foreground sm:text-sm"
							htmlFor="hours"
						>
							Active hours per day
						</OnboardingLabel>
						<div className="flex flex-nowrap gap-4">
							<OnboardingSlider
								value={activeHours}
								onValueChange={setActiveHours}
								id="hours"
								defaultValue={[8]}
								max={24}
								step={1}
								aria-valuetext={`${activeHours[0]} hours`}
							/>
							<div className="flex h-8 w-12 items-center justify-center rounded border border-border bg-background text-sm font-medium text-foreground">
								<span aria-hidden="true">{activeHours}h</span>
							</div>
						</div>
					</div>

					<OnboardingCard
						className="mt-4 space-y-1 border-border motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-4"
						style={{
							animationDuration: "500ms",
							animationDelay: "1000ms",
							animationFillMode: "backwards",
						}}
					>
						<p className="text-muted-foreground sm:text-sm">
							Estimated monthly cost
						</p>
						<p
							className="text-3xl font-medium text-foreground sm:text-2xl"
							aria-live="polite"
						>
							{price}
						</p>
					</OnboardingCard>

					<div
						className={cx(
							"mt-6 flex",
							backButton ? "justify-between" : "justify-end",
						)}
					>
						{backButton && (
							<OnboardingButton
								type="button"
								variant="ghost"
								onClick={backButton.onClick}
							>
								{backButton.text}
							</OnboardingButton>
						)}
						<OnboardingButton
							className="disabled:bg-muted disabled:text-muted-foreground"
							type="submit"
							disabled={!isValid || loading}
							aria-disabled={!isValid || loading}
							isLoading={loading}
						>
							{loading ? loadingText : submitText}
						</OnboardingButton>
					</div>
				</div>
			</form>
		</main>
	);
}
