import React, { useCallback, useEffect } from 'react';
import { createRoot } from 'react-dom/client';

import './scss/style.scss';

import ApuraRangeControl from './components/ApuraRangeControl';
import ApuraColor from './components/ApuraColor';
import ApuraColors from './components/ApuraColors';
import ApuraSortable from './components/ApuraSortable';
import ApuraButtonGroup from './components/ApuraButtonGroup';
import ApuraToggle from './components/ApuraToggle';
import ApuraImageButtonGroup from './components/ApuraImageButtonGroup';

import ApuraPaletteOverrides from './components/ApuraPaletteOverrides';
import ApuraCustomPalette from './components/ApuraCustomPalette';
import ApuraTypography from './components/ApuraTypography';
import GoogleFontSettings from './components/GoogleFontSettings';
import ApuraText from './components/ApuraText';
import ApuraTabs from './components/ApuraTabs';

import { parseCssValue, createDeviceValue } from './components/utils';

import ApuraSectionNavigation from './components/ApuraSectionNavigation';

import { __, sprintf, _x } from '@wordpress/i18n';

// React Rootsを管理するためのWeakMap
const rootsMap = new WeakMap();

function renderControl(controls: any, type: string, renderCallback: (control: any) => JSX.Element) {
	const ids = Object.keys(controls).filter(key => controls[key].type === type);

	ids.forEach(id => {
		const control = wp.customize.control(id);
		const field = document.querySelector(control.selector);

		if (!field) return;

		// 既存のRootが存在するかチェック
		let root = rootsMap.get(field);
		if (!root) {
			root = createRoot(field);
			rootsMap.set(field, root);
		}

		root.render(renderCallback(control));
	});
}

function getDevices(control: any): devices {
	const devices : devices = [];
	if (control.params.settings.hasOwnProperty('desktop')) {
		devices.push({ device: 'desktop', label: __('Desktop', 'apura') });
	}
	if (control.params.settings.hasOwnProperty('tablet')) {
		devices.push({ device: 'tablet', label: __('Tablet', 'apura') });
	}
	if (control.params.settings.hasOwnProperty('mobile')) {
		devices.push({ device: 'mobile', label: __('Mobile', 'apura') });
	}

	return devices;
}

function getUnitOptions(sizeUnits: unitData[]) {
	return (sizeUnits || []).map((unit: unitData) => ({
		label: unit?.label ?? unit?.value,
		value: unit?.value
	}));
}


function renderRangeControls(controls: any) {
	renderControl(controls, 'apura-range-control', (control) => {
		const params = control.params;
		const sizeUnits: unitData[] = params?.choices?.sizeUnits;
		const devices: devices = getDevices(control);

		const values: RangeControlDeviceValue[] = [];
		const defaults: RangeControlDeviceValue[] = [];

		devices.forEach(({ device }) => {
			let currentValue = control.settings[device].get();
			// console.log(currentValue);
			const parsedValue = currentValue ? parseCssValue(currentValue) : { value: null, unit: sizeUnits[0].value || '-' };
			const parsedDefaults = params[device]?.default ? parseCssValue(params[device]?.default) : { value: null, unit: sizeUnits[0].value || '-' };

			const { value, default: defaultValue } = createDeviceValue(device, parsedValue, parsedDefaults, sizeUnits);
			values.push(value);
			defaults.push(defaultValue);
		});

		return (
			<ApuraRangeControl
				values={values}
				defaults={defaults}
				devices={devices}
				unitData={sizeUnits}
				label={params.label}
				unitOptions={getUnitOptions(sizeUnits)}
				onChange={(newValues) => {
					devices.forEach(device => {
						// console.log(newValues[device.device]);
						control.settings[device.device].set(newValues[device.device]);
					});
				}}
			/>
		)
	}
	);
}


function renderPaletteOverridesControls(controls: Controls) {
	renderControl(controls, 'apura-palette-overrides', (control) => {
		// console.log(control);
		return (
			<ApuraPaletteOverrides
				controlSetting={control.setting}
				values={control.setting.get()}
					palette={apuraCustomizerControl.builtInPalette}
				title={control.params.label}
				description={control.params.description}
			/>
		)
	});
}

function renderCustomPaletteControls(controls: Controls) {
	renderControl(controls, 'apura-custom-palette', (control) => {
		// console.log(control);
		return (
			<ApuraCustomPalette
				controlSetting={control.setting}
				values={control.setting.get()}
				resetDefaults={control.params.default}
				title={control.params.label}
				description={control.params.description}
			/>
		)
	});
}


function renderColorControls(controls: any) {
	renderControl(controls, 'apura-color', (control) => (
		<ApuraColor
			controlSetting={control.setting}
			value={control.setting.get()}
			resetDefault={control.params.default}
			title={control.params.label}
			description={control.params.description}
		/>
	));
}

function renderColorsControls(controls: any) {
	renderControl(controls, 'apura-colors', (control) => (
		<ApuraColors
			controlSettings={control.settings}
			fields={control.params.fields}
			title={control.params.label}
			description={control.params.description}
		/>
	));
}


type ControlParams = {
  label: string;
  sort_label: string;
  description: string;
  choices: { [key: string]: string };
};

type Control = {
  type: string;
  selector: string;
  setting: {
    get: () => string[];
		set: () => void;
  };
  params: ControlParams;
};

type Controls = {
  [key: string]: Control;
};


interface Choice {
  value: string;
  label: string;
  subControls?: string[];
}

function renderSortableControls(controls: Controls) {

	renderControl(controls, 'apura-sortable', (control) => {
		const { params, setting, selector } = control;
		// optionの値
		const values: string[] = setting.get();
		const valueSet = new Set(values);

		const disabledSort: string[] = control.params.disabledSort || [];
		const lockedItems = control.params.lockedItems || [];

		let items: SortItems;

		if (values.length === 0) {
			// 初期値が空の場合、choices の順番で設定
			items = params.choices.map((item: Choice) => ({
				id: item.value,
				label: item.label,
				value: item.value,
				isActive: false,
				subControls: item?.subControls || null,
			}));
		} else {
			// values にある順で並び替え（順番維持）
			const orderedItems: SortItems = values
				.map((id) => {
					const item: SortableItem = params.choices.find((choice: Choice) => choice.value === id);
					if (!item) return null;
					return {
						id: item.value,
						label: item.label,
						value: item.value,
						isActive: true,
						subControls: item?.subControls || null,
					};
				})
				.filter((item) => item !== null); // null を除外

			// values に含まれていない choices を後ろに追加
			const remainingItems: SortItems = params.choices
				.filter((choice: Choice) => !valueSet.has(choice.value))
				.map((item: Choice) => ({
					id: item.value,
					label: item.label,
					value: item.value,
					isActive: false,
					subControls: item?.subControls || null,
				}));

			items = [...orderedItems, ...remainingItems];
		}

		return (
			<ApuraSortable
				values={items}
				title={control.params.label}
				description={control.params.description}
				disabledSort={disabledSort}
				lockedItems={lockedItems}
				choices={params.choices}
				onChange={(newValues) => {
					setting.set(newValues);
				}}
			/>
		);
	});
}


type radioButtonsChoices = {
  [key: string]: string
};
function renderButtonGroupControls(controls: Controls) {
	renderControl(controls, 'apura-button-group', (control) => {
		// console.log(control);
		const choices: radioButtonsChoices = control.params.choices;
		return (
			<ApuraButtonGroup
				controlSetting={control.setting}
				choices={choices}
				value={control.setting.get()}
				title={control.params.label}
				description={control.params.description}
			/>
		)
	});
}


type imageButtonsChoices = {
	[key: string]: {
		label: string,
		title: string,
		image: string
	}
};
function renderImageButtonGroupControls(controls: Controls) {
	renderControl(controls, 'apura-image-button-group', (control) => {
		const choices: imageButtonsChoices = control.params.choices;
		return (
			<ApuraImageButtonGroup
				controlSetting={control.setting}
				choices={choices}
				value={control.setting.get()}
				title={control.params.label}
				description={control.params.description}
				col={control.params.col}
			/>
		)
	});
}

function renderToggleControls(controls: Controls) {
	renderControl(controls, 'apura-toggle', (control) => {
		return (
			<ApuraToggle
				controlSetting={control.setting}
				isActive={control.setting.get()}
				title={control.params.label}
				description={control.params.description}
			/>
		)
	});
}

// このコントロールはサイトに一つだけ。
function renderGoogleFontSettingsControl(controls: Controls) {
	const id = Object.keys(controls).find(key => controls[key].type === 'apura-google-font-settings');

	if (!id) return;

	const control = wp.customize.control(id);
	const field = document.querySelector(control.selector);

	if (!field) return;

	// 既存のRootが存在するかチェック
	let root = rootsMap.get(field);
	if (!root) {
		root = createRoot(field);
		rootsMap.set(field, root);
	}

	const choices = control.params?.choices;
	const fonts = Object.keys(choices)?.map(key => ({ label: key, value: key }));
	const variants = Object.keys(choices)?.map(key => ({
		type: choices[key].type,
		name: key,
		category: choices[key].category,
		variants: choices[key].variants,
		italic: choices[key]?.italic || '',
		optical_size: choices[key]?.optical_size || '',
		width: choices[key]?.width || '',
	}));

	root.render(
		<GoogleFontSettings
			values={control.setting.get()}
			defaults={control.settings.default.get()}
			fonts={fonts}
			fontVariants={variants}
			title={control.params.label}
			description={control.params.description}
			onChange={(newValues) => {
				control.setting.set(newValues);
			}}
		/>
	);
}

function renderTypographyControls(controls: Controls) {
	renderControl(controls, 'apura-typography', (control) => {
		const exclude: string[] = control.params?.choices?.exclude || [];
		return (
			<ApuraTypography
				values={control.setting.get()}
				defaults={control.params.default}
				title={control.params.label}
				description={control.params.description}
				exclude={exclude}
				onChange={(newValues) => {
					control.setting.set(newValues);
				}}
			/>
		)
	});
}

function renderTextControls(controls: Controls) {
	renderControl(controls, 'apura-text', (control) => {
		// console.log(control);
		return (
			<ApuraText
				value={control.setting.get()}
				title={control.params.label}
				description={control.params.description}
				onChange={(newValue) => {
					control.setting.set(newValue);
				}}
			/>
		)
	});
}

function renderTabsControls(controls: Controls) {
	renderControl(controls, 'apura-tabs', (control) => {
		// console.log(control.params.tabs);

		return (
			<ApuraTabs
				tabs={control.params.tabs}
				description={control.params.description}
			/>
		)
	});
}

/**
 * Section Navigation コントロールのレンダリング
 */
function renderSectionNavigationControls(controls: Controls) {
	renderControl(controls, 'apura-section-navigation', (control) => {
		const navigationConfig = control.params.navigationConfig;

		const handleNavigate = (sectionId: string) => {
			navigateToSection(sectionId);
		};

		return (
			<ApuraSectionNavigation
				navigationConfig={navigationConfig}
				onNavigate={handleNavigate}
			/>
		);
	});
}



wp.customize.bind('ready', function() {
	const controls = wp.customize.settings.controls;

	renderRangeControls(controls);
	renderColorControls(controls);
	renderColorsControls(controls);
	renderSortableControls(controls);
	renderButtonGroupControls(controls);
	renderImageButtonGroupControls(controls);
	renderToggleControls(controls);

	renderTypographyControls(controls);

	renderPaletteOverridesControls(controls);
	renderCustomPaletteControls(controls);

	renderTextControls(controls);

	// 一つだけ表示されるコントロール.
	renderGoogleFontSettingsControl(controls);

	renderTabsControls(controls);

	renderSectionNavigationControls(controls);

});

/**
 * シンプルなセクション移動機能
 *
 * @since 1.0.0
 *
 * @param {string} sectionId 移動先セクションID
 */
function navigateToSection(sectionId: string) {
	if (!wp?.customize?.section) {
		console.error('WordPress Customizer API not available');
		return;
	}

	const targetSection = wp.customize.section(sectionId);
	if (!targetSection) {
		console.error(`Target section not found: ${sectionId}`);
		return;
	}

	// セクションにフォーカスを移動
	targetSection.focus();
}
