import React, { type ReactNode, useEffect } from "react";
import type { SupportedLocale } from "./LocalizationProvider";

export interface Token {
	address: string;
	chainId: number;
	decimals: number;
	logoURI: string;
	name: string;
	symbol: string;
	amount?: number; // for input/output amoutns
	balance?: string;
	balanceInUsd?: number;
	tags?: string[];
}

export interface Theme {
	/**
	 * @default 420
	 */
	width?: "full" | number;

	/**
	 * @default "base"
	 */
	borderRadius?: "none" | "sm" | "base" | "md" | "lg";

	fonts?: {
		primary?: string;
		secondary?: string;
	};

	/**
	 * Supports hex and rgb format
	 *
	 * #FFFFFF or rgb(255, 255, 255)
	 */
	colors?: {
		bgLayer1?: string;
		bgLayer2?: string;
		bgLayer3?: string;
		textPrimary?: string;
		textSecondary?: string;
		themePrimary?: string;
		border?: string;
		icon?: string;
		accent?: string;
		accentBg?: string;
		accent2?: string;
		accentBg2?: string;
		success?: string;
	};
}

export interface BungeeConfig {
	apiKey: string;

	initialValues?: {
		fromChain?: number;
		inputTokens?: string[];
		toChain?: number;
		outputTokens?: string[];
		amount?: string[];
		outputRatio?: number[];
		locale?: SupportedLocale; // need validation
		sortPreference?: "fast" | "best";
		swapSlippage?: number;
	};

	features?: {
		autoRouting?: boolean; // I think a flag is needed to turn off the feature, probably shouldn't expose it though
		refuel?: boolean; //
		internalTxHistory?: boolean;
	};

	// Services to include/exclude (defaults to all supported)
	includeDexes?: string[];
	excludeDexes?: string[];
	includeBridges?: string[];
	excludeBridges?: string[];

	// Supported tokens and chains
	/** Supported tokens - pass the token addresses */
	supportedTokens?: {
		from?: { [chainId: string]: string[] };
		to?: { [chainId: string]: string[] };
	};
	supportedChains?: {
		from?: number[];
		to?: number[];
	};
	// tokenList?: string | Token[]; // string for URL, Token[] for custom data

	// Fee parameters
	feeParams?: {
		feeTakerAddress?: string;
		feePercent?: number;
	};

	// Destination payload (optional)
	destinationPayload?: string;

	// Theme customization (collaborate with designer)
	theme?: Theme;

	// Event handlers
	//   onSwapApproval?: (data: SwapApprovalData) => void; // More descriptive name
	//   onOrderPlacement?: (data: OrderPlacementData) => void; // More descriptive name
	//   onFromTokenChange?: (data: FromTokenChangeData) => void; // More descriptive name
	//   onToTokenChange?: (data: ToTokenChangeData) => void; // More descriptive name
	//   onError?: (error: ErrorData) => void; // Provides error object with message and code

	// External transaction history (optional)
	openTxItem?: number; // might need some changes

	// Branding and base URL (optional)
	removeBranding?: boolean;
	baseUrl?: string;

	// Temporary
	maxCap?: number;
}

export const WidgetConfigContext = React.createContext<BungeeConfig | null>(
	null,
);

export const ConfigProvider = ({
	children,
	config,
}: { children: ReactNode; config: BungeeConfig | null }) => {
	useEffect(() => {
		if (config?.theme) {
			setCssVariables(config.theme);
		}
	}, [config]);

	return (
		<WidgetConfigContext.Provider value={config}>
			{children}
		</WidgetConfigContext.Provider>
	);
};

function isHexCode(str: string) {
	const regex = /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i;
	return regex.test(str);
}

function isRgbCode(str: string) {
	const regex = /^rgb\(\s*(?:\d{1,3}\s*,\s*){2}\d{1,3}\s*\)$/i;
	return regex.test(str);
}

function formatRGB(colorCode: string) {
	if (isHexCode(colorCode)) {
		// Remove leading #
		const hex = colorCode.replace(/^#?/, "");

		// Convert each two-digit hex pair to decimal using parseInt
		const r = Number.parseInt(hex.substring(0, 2), 16);
		const g = Number.parseInt(hex.substring(2, 4), 16);
		const b = Number.parseInt(hex.substring(4, 6), 16);

		return [r, g, b].join(" ");
	}

	if (isRgbCode(colorCode)) {
		return colorCode
			.split(",")
			.map((x) => x.replace(/[^0-9.]/g, ""))
			.join(" ");
	}

	throw new Error("Invalid code code. Supports hex and rgb formats");
}

function updateCssVariable(variableName: string, newValue: string) {
	document
		.getElementById("bn-swap-wrap")
		?.style.setProperty(variableName, newValue);
}

const colorVariableNames = [
	"textPrimary",
	"textSecondary",
	"bgLayer1",
	"bgLayer2",
	"bgLayer3",
	"borderPrimary",
	"icon",
	"accent",
	"accentBg", // @todo - add all color tokens
	"accent2",
	"accentBg2",
];

const fontVariableNames = ["primary", "secondary"];

function setCssVariables(theme: Theme) {
	// To set CSS color variables
	const colors = theme?.colors;
	const fonts = theme?.fonts;

	for (const colorName of colorVariableNames) {
		const colorValue = colors?.[colorName as keyof typeof colors];

		if (colorValue) {
			// biome-ignore format:
			const cssVariableName = `--bn-${colorName}`;
			updateCssVariable(cssVariableName, formatRGB(colorValue));
		}
	}

	for (const fontName of fontVariableNames) {
		const fontValue = fonts?.[fontName as keyof typeof fonts];

		if (fontValue) {
			// biome-ignore format:
			const cssVariableName = `--bn-font-${fontName}`
			updateCssVariable(cssVariableName, fontValue);
		}
	}
}
