import { plusCircle } from '@wordpress/icons';
import {
	Button,
	Card,
	CardBody,
	Flex,
	Icon,
	Modal,
	Notice,
	TextControl,
} from '@wordpress/components';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { formatCurrency } from '../utils';
import { PrepayAPI, PrePayBalance, TopUpOrder } from '../../types';
import { Spinner } from '@woocommerce/components';
import PaymentCore from './payment/payment-core';
import z from 'zod';
import { useWindowSize } from '../hooks';

interface PrepayTopUpProps {
	prepayBalance: PrePayBalance;
	loading?: boolean;
	error?: string | null;
	onTopUpSuccess?: () => void;
	createTopUp: PrepayAPI['createTopUp'];
	Wrapper: React.ComponentType<{ children: React.ReactNode }>;
}

const customeAmountSchema = z
	.number()
	.min(20, { message: 'Amount must be at least £20' })
	.max(1000000, {
		message: 'Amount must be less than or equal to £1,000,000',
	});

export default function PrepayTopUp({
	prepayBalance,
	createTopUp,
	loading = false,
	error = null,
	onTopUpSuccess,
	Wrapper,
}: PrepayTopUpProps) {
	const [isCustomTopUpModalOpen, setIsCustomTopUpModalOpen] =
		useState<boolean>(false);
	const [topUpAmount, setTopUpAmount] = useState<number>(20);
	const [topUpSuccess, setTopUpSuccess] = useState<boolean>(false);
	const [topUpOrder, setTopUpOrder] = useState<TopUpOrder | null>(null);
	const [validationError, setValidationError] = useState<string | null>(null);
	const { isSmOrUp, isLgOrUp } = useWindowSize();

	// Sync topUpAmount when prepayBalance loads
	useEffect(() => {
		if (prepayBalance?.minimumTopUp) {
			setTopUpAmount(prepayBalance.minimumTopUp);
		}
	}, [prepayBalance?.minimumTopUp]);

	const topUpCurrency = prepayBalance?.currency || 'GBP';
	const minimumTopUp = prepayBalance?.minimumTopUp || 20;

	const topUpAmounts = useMemo(
		() =>
			prepayBalance?.minimumTopUp
				? [1, 2.5, 5].map((m) => prepayBalance.minimumTopUp * m)
				: [],
		[prepayBalance?.minimumTopUp]
	);

	const topUpDescription = useMemo(
		() =>
			prepayBalance &&
			typeof prepayBalance.freePercentage === 'number' &&
			typeof prepayBalance.freeThreshold === 'number'
				? sprintf(
						/* translators: 1: percent, 2: formatted money threshold */
						__(
							'Get up to %1$s%% extra every time you top up %2$s or more.',
							'parcel2go-shipping'
						),
						String(prepayBalance.freePercentage),
						formatCurrency(
							prepayBalance.freeThreshold,
							prepayBalance.currency
						)
					)
				: '',
		[
			prepayBalance?.freePercentage,
			prepayBalance?.freeThreshold,
			prepayBalance?.currency,
		]
	);

	const handlePaymentSuccess = useCallback(() => {
		setTopUpSuccess(true);
		setTopUpOrder(null);
		onTopUpSuccess?.();
	}, [onTopUpSuccess]);

	const closePaymentModal = useCallback(() => {
		setTopUpOrder(null);
	}, []);

	const handleAddBalance = useCallback(
		async (amount: number) => {
			const validation = customeAmountSchema.safeParse(amount);
			if (!validation.success) {
				setValidationError(
					validation.error.issues[0]?.message || 'Invalid amount'
				);
				return;
			}
			const result = await createTopUp(amount, minimumTopUp);
			if (result) {
				setTopUpOrder(result);
			}
			if (isCustomTopUpModalOpen) {
				setIsCustomTopUpModalOpen(false);
			}
		},
		[createTopUp, minimumTopUp, isCustomTopUpModalOpen]
	);

	if (error) return null;

	return (
		<Wrapper>
			<Flex
				direction="column"
				align="flex-start"
				gap={4}
				style={{ width: '100%' }}
			>
				<Flex
					direction="column"
					gap={2}
					align="flex-start"
					justify="flex-start"
				>
					<Flex
						align="center"
						justify="flex-start"
						direction="row"
						gap={2}
					>
						<Icon icon={plusCircle} size={28} />
						<span
							style={{
								fontWeight: 600,
								fontSize: '0.9375rem',
							}}
						>
							{__('Choose top up amount', 'parcel2go-shipping')}
						</span>
					</Flex>

					{loading && !error ? (
						<Flex style={{ padding: 16 }}>
							<Spinner />
						</Flex>
					) : (
						<>
							<p
								style={{
									margin: 0,
									fontSize: 13,
									color: '#646970',
									lineHeight: 1.5,
								}}
							>
								{topUpDescription}
							</p>
							{(error || validationError) && (
								<Notice status="error" isDismissible={false}>
									{error || validationError}
								</Notice>
							)}
							{topUpSuccess && (
								<Notice status="success" isDismissible={false}>
									{__(
										'Prepay balance topped up successfully',
										'parcel2go-shipping'
									)}
								</Notice>
							)}
						</>
					)}
				</Flex>

				{!loading && !error && (
					<div
						style={{
							width: '100%',
							display: 'grid',
							gap: 4,
							gridTemplateColumns:
								isSmOrUp && !isLgOrUp
									? 'repeat(2, minmax(0, 1fr))'
									: 'repeat(4, minmax(0, 1fr))',
							marginTop: 'auto',
							minHeight: 'auto',
						}}
					>
						{topUpAmounts.map((amt) => (
							<Button
								key={amt}
								variant="secondary"
								size="compact"
								onClick={() => void handleAddBalance(amt)}
								disabled={loading}
								isBusy={loading}
								style={{ justifyContent: 'center' }}
							>
								{formatCurrency(amt, topUpCurrency)}
							</Button>
						))}
						<Button
							variant="secondary"
							size="compact"
							onClick={() => setIsCustomTopUpModalOpen(true)}
							isBusy={loading}
							disabled={loading}
							style={{ justifyContent: 'center' }}
						>
							{__('Custom', 'parcel2go-shipping')}
						</Button>
					</div>
				)}
			</Flex>

			{isCustomTopUpModalOpen && !topUpOrder && (
				<Modal
					size="large"
					title={__('Top up amount', 'parcel2go-shipping')}
					onRequestClose={() => setIsCustomTopUpModalOpen(false)}
					shouldCloseOnClickOutside={false}
				>
					<Card style={{ background: '#f6f7f7' }}>
						<CardBody>
							<p
								className="components-base-control__help"
								style={{ marginTop: 0 }}
							>
								{topUpDescription}
							</p>
							<TextControl
								label={sprintf(
									__(
										'Amount (minimum %s)',
										'parcel2go-shipping'
									),
									formatCurrency(minimumTopUp, topUpCurrency)
								)}
								type="number"
								value={String(topUpAmount)}
								onChange={(value) =>
									setTopUpAmount(Number(value))
								}
								min={minimumTopUp}
								step={1}
							/>
						</CardBody>
					</Card>
					{(error || validationError) && (
						<Notice status="error" isDismissible={false}>
							{error || validationError}
						</Notice>
					)}
					<Flex justify="flex-end" gap={2}>
						<Button
							variant="primary"
							onClick={() => void handleAddBalance(topUpAmount)}
							disabled={loading || topUpAmount < minimumTopUp}
							isBusy={loading}
						>
							{__('Top up', 'parcel2go-shipping')}
						</Button>
					</Flex>
				</Modal>
			)}

			{topUpOrder && (
				<Modal
					size="large"
					title={sprintf(
						__('Confirm Payment of %s', 'parcel2go-shipping'),
						formatCurrency(topUpOrder.amount, topUpCurrency)
					)}
					onRequestClose={closePaymentModal}
					isDismissible
					shouldCloseOnClickOutside={false}
				>
					<PaymentCore
						paymentOrder={{
							orderResult: topUpOrder.order.result,
						}}
						onSuccess={handlePaymentSuccess}
					/>
				</Modal>
			)}
		</Wrapper>
	);
}
