<script lang="ts">
	import { onMount } from 'svelte';
	import { page } from '$app/stores';
	import { goto } from '$app/navigation';
	import { get } from 'svelte/store';
	import { addNotification } from '$lib/core/stores/noti.js';
	import { departmentStore } from '$lib/core/stores/departments.js';
	import { permission as currentPerms } from '$lib/core/stores/permissions.js';
	import { referenceFromPage } from '$lib/core/stores/recipeStore.js';
	import {
		existingProductCodes,
		getPriceColumnIndex,
		getCountryPrimaryLanguage,
		getPriceFromCells,
		lastRequestSheetPrice,
		priceSlotNamespaces,
		priceSlots,
		priceSlotsError,
		priceSlotsLoading,
		sheetPriceAllRows,
		sheetPriceHeader,
		sheetPriceLoading,
		type GristCell,
		type PriceSlot,
		type PriceSlotProduct,
		type PriceSlotServiceRow
	} from '$lib/core/stores/sheetStore.js';
	import {
		addPriceSlot,
		addPriceSlotRows,
		deletePriceSlotRows,
		requestListMenu,
		requestPriceSlot,
		requestPriceSlots,
		requestSheetPrice,
		updatePriceSlot
	} from '$lib/core/services/sheetService.js';
	import { waitForAuthenticatedSocket } from '$lib/core/stores/websocketStore.js';

	import Button from '$lib/components/ui/button/button.svelte';
	import Input from '$lib/components/ui/input/input.svelte';
	import * as Dialog from '$lib/components/ui/dialog/index.js';
	import * as Select from '$lib/components/ui/select/index.js';
	import * as Table from '$lib/components/ui/table/index.js';
	import Badge from '$lib/components/ui/badge/badge.svelte';
	import {
		Calculator,
		Plus,
		RefreshCw,
		Save,
		RotateCcw,
		Search,
		Trash2
	} from '@lucide/svelte/icons';

	type AdjustmentMode =
		| 'increase_percent'
		| 'increase_amount'
		| 'decrease_percent'
		| 'decrease_amount';

	const adjustmentModeLabels: Record<AdjustmentMode, string> = {
		increase_percent: 'Increase by Percentage (%)',
		increase_amount: 'Increase by Fixed Amount',
		decrease_percent: 'Decrease by Percentage (%)',
		decrease_amount: 'Decrease by Fixed Amount'
	};

	const emptySlot: PriceSlot = {
		slot: 0,
		name: '',
		description: '',
		kind: 'price',
		header: [],
		products: []
	};
	const rowsPerPage = 200;
	const supportedCountries = new Set([
		'aus',
		'gbr',
		'hkg',
		'ltu',
		'mys',
		'rou',
		'sgp',
		'tha',
		'uae_dubai'
	]);

	let selectedCountry = $state<string>($page.params.country || get(departmentStore) || '');
	let enabledCountries = $state<string[]>([]);
	let selectedSlot = $state(0);
	let localSlots = $state<PriceSlot[]>([]);
	let workingSlot = $state<PriceSlot | null>(null);
	let savedSlot = $state<PriceSlot | null>(null);
	let saveLoading = $state(false);
	let productCodeSearch = $state('');
	let createDialogOpen = $state(false);
	let adjustmentMode = $state<AdjustmentMode>('increase_percent');
	let adjustmentValue = $state(15);
	let createSlotNumber = $state(1);
	let createName = $state('ProfileIncrease15');
	let createDescription = $state('increase price 15%');
	let productPage = $state(1);
	let servicePage = $state(1);
	let requestedSlotKeys = new Set<string>();
	let requestedProductCodeCountries = new Set<string>();
	let requestedPriceCountries = new Set<string>();
	let pendingCreateDialog = $state(false);
	let deletedProductRowIds = $state<number[]>([]);
	let createMode = $state<'from_price' | 'blank'>('from_price');
	let addDialogOpen = $state(false);
	let addProductCode = $state('');
	let addProductName = $state('');
	let addProductPrice = $state('');

	let selectedCountryKey = $derived(selectedCountry.toLowerCase());
	let selectedCountryLanguage = $derived(getCountryPrimaryLanguage(selectedCountry));
	let backendSlots = $derived($priceSlots[selectedCountryKey] ?? []);
	let namespaceSlots = $derived($priceSlotNamespaces[selectedCountryKey] ?? []);
	let displaySlots = $derived(
		mergeDisplaySlots(namespaceSlots, backendSlots, localSlots).sort((a, b) => a.slot - b.slot)
	);
	let selectedSourceSlot = $derived(
		displaySlots.find((slot) => slot.slot === selectedSlot) ?? displaySlots[0] ?? null
	);
	let currentSlot = $derived(workingSlot ?? emptySlot);
	let isServiceSlot = $derived(currentSlot.kind === 'service');
	let serviceHeaders = $derived(currentSlot.header?.filter(Boolean) ?? []);
	let loading = $derived($priceSlotsLoading);
	let basePriceCells = $derived(
		$lastRequestSheetPrice[selectedCountry.toLowerCase()] ||
			$lastRequestSheetPrice[selectedCountry] ||
			{}
	);
	let basePriceRows = $derived(
		$sheetPriceAllRows[selectedCountry.toLowerCase()] || $sheetPriceAllRows[selectedCountry] || {}
	);
	let basePriceRowCount = $derived(
		Object.values(basePriceRows).reduce((total, rows) => total + rows.length, 0)
	);
	let basePriceHeader = $derived(
		$sheetPriceHeader[selectedCountry.toLowerCase()] || $sheetPriceHeader[selectedCountry] || []
	);
	let createPriceBaseLoading = $derived($sheetPriceLoading);
	let filteredProducts = $derived(
		currentSlot.products.filter((product) => {
			const keyword = productCodeSearch.trim().toLowerCase();
			if (!keyword) return true;

			return product.product_code.toLowerCase().includes(keyword);
		})
	);
	let filteredServiceRows = $derived(
		(currentSlot.serviceRows ?? []).filter((row) => {
			const keyword = productCodeSearch.trim().toLowerCase();
			if (!keyword) return true;

			return Object.values(row.cells).some((value) => value.toLowerCase().includes(keyword));
		})
	);
	let productPageCount = $derived(Math.max(1, Math.ceil(filteredProducts.length / rowsPerPage)));
	let servicePageCount = $derived(Math.max(1, Math.ceil(filteredServiceRows.length / rowsPerPage)));
	let pagedProducts = $derived(
		filteredProducts.slice((productPage - 1) * rowsPerPage, productPage * rowsPerPage)
	);
	let pagedServiceRows = $derived(
		filteredServiceRows.slice((servicePage - 1) * rowsPerPage, servicePage * rowsPerPage)
	);
	let changedCount = $derived(countChangedProducts(currentSlot, savedSlot ?? undefined));
	let changedServiceCount = $derived(countChangedServiceRows(currentSlot, savedSlot ?? undefined));
	let addedProductCount = $derived(countAddedProducts(currentSlot, savedSlot ?? undefined));
	let deletedProductCount = $derived(deletedProductRowIds.length);
	let totalChangedCount = $derived(
		changedCount + changedServiceCount + addedProductCount + deletedProductCount
	);
	let isLocalSlot = $derived(localSlots.some((slot) => slot.slot === currentSlot.slot));
	let visibleRowCount = $derived(
		isServiceSlot ? filteredServiceRows.length : filteredProducts.length
	);
	let totalRowCount = $derived(
		isServiceSlot ? (currentSlot.serviceRows?.length ?? 0) : currentSlot.products.length
	);
	let hasHeaderChanges = $derived(
		currentSlot.name !== savedSlot?.name || currentSlot.description !== savedSlot?.description
	);
	let hasChanges = $derived(totalChangedCount > 0 || hasHeaderChanges || isLocalSlot);
	let resetButtonTitle = $derived(
		!currentSlot.slot
			? 'Select a PriceSlot first'
			: !savedSlot
				? 'This PriceSlot has not been saved yet'
				: !hasChanges
					? 'Reset is available after changing this PriceSlot'
					: 'Discard unsaved changes and restore the last loaded values'
	);

	function getEnabledSheetCountries() {
		return get(currentPerms)
			.filter((x) => x.startsWith('document.write'))
			.map((x) => x.split('.')[2])
			.filter((country) => supportedCountries.has(country));
	}

	onMount(() => {
		referenceFromPage.set('priceslot');

		if (selectedCountry) {
			departmentStore.set(selectedCountry);
		}

		enabledCountries = getEnabledSheetCountries();

		if (selectedCountry) {
			void loadPriceSlots();
		}
	});

	let lastLoadedSlotSignature = $state('');

	$effect(() => {
		if (displaySlots.length === 0) {
			workingSlot = null;
			savedSlot = null;
			lastLoadedSlotSignature = '';
			return;
		}

		if (!displaySlots.some((slot) => slot.slot === selectedSlot)) {
			selectedSlot = displaySlots[0]?.slot ?? 0;
			return;
		}

		if (!selectedSourceSlot) return;

		const signature = getSlotSignature(selectedSourceSlot);
		if (signature === lastLoadedSlotSignature) return;
		if (hasChanges && workingSlot?.slot === selectedSourceSlot.slot) return;

		lastLoadedSlotSignature = signature;
		workingSlot = clonePriceSlot(selectedSourceSlot);
		savedSlot = clonePriceSlot(selectedSourceSlot);
		deletedProductRowIds = [];
		productCodeSearch = '';
		productPage = 1;
		servicePage = 1;
		void ensureSelectedSlotLoaded(selectedSourceSlot);
	});

	$effect(() => {
		if (!pendingCreateDialog) return;

		if (basePriceRowCount > 0) {
			pendingCreateDialog = false;
			applyCreateTemplate();
			createDialogOpen = true;
			return;
		}

		if (!$sheetPriceLoading) {
			const productCodes = getProductCodesForPriceBase();
			if (productCodes.length > 0) void requestPriceBaseFromProductCodes(productCodes);
		}
	});

	$effect(() => {
		if (currentSlot.products.length === 0) return;
		if (requestedPriceCountries.has(selectedCountryKey)) return;
		if (isLocalSlot) return;
		if (Object.keys(basePriceCells).length > 0) return;

		const productCodes = currentSlot.products
			.filter((p) => p.product_code)
			.map((p) => p.product_code);
		if (productCodes.length === 0) return;

		void requestPriceBaseFromProductCodes(productCodes);
	});

	function getBaseProducts(): (PriceSlotProduct & { sourceCells: GristCell[] })[] {
		return Object.entries(basePriceRows).flatMap(([productCode, rows]) =>
			rows.map((row) => {
				const productName = getCellValue(row.cells, 2);
				const price = getPriceFromCells(selectedCountryKey, row.cells, 'cash_price');
				const parsedPrice = Number(price);

				return {
					product_code: productCode,
					name: productName,
					price: Number.isNaN(parsedPrice) ? null : parsedPrice,
					row_index: row.row,
					sourceCells: row.cells
				};
			})
		);
	}

	function mergeDisplaySlots(
		namespaces: PriceSlot[],
		loadedSlots: PriceSlot[],
		draftSlots: PriceSlot[]
	) {
		const merged = new Map<number, PriceSlot>();
		for (const slot of namespaces) merged.set(slot.slot, slot);
		for (const slot of loadedSlots) merged.set(slot.slot, slot);
		for (const slot of draftSlots) merged.set(slot.slot, slot);
		return Array.from(merged.values());
	}

	function getSlotSignature(slot: PriceSlot) {
		return [
			slot.slot,
			slot.name,
			slot.description,
			slot.kind ?? '',
			slot.products.length,
			slot.serviceRows?.length ?? 0
		].join('|');
	}

	function isSlotDataLoaded(slot: PriceSlot) {
		return (
			(slot.header?.length ?? 0) > 0 ||
			slot.products.length > 0 ||
			(slot.serviceRows?.length ?? 0) > 0
		);
	}

	async function ensureSelectedSlotLoaded(slot: PriceSlot) {
		if (!slot.slot || isLocalSlot || isSlotDataLoaded(slot)) return;

		const requestKey = `${selectedCountryKey}:${slot.slot}`;
		if (requestedSlotKeys.has(requestKey)) return;

		requestedSlotKeys.add(requestKey);
		const sent = await requestPriceSlot(selectedCountry, slot.slot);
		if (!sent) {
			requestedSlotKeys.delete(requestKey);
			addNotification(`ERR:Failed to request PriceSlot${slot.slot}`);
		}
	}

	function getBasePrice(product: PriceSlotProduct): number | null {
		const productWithSource = product as PriceSlotProduct & { sourceCells?: GristCell[] };
		if (productWithSource.sourceCells?.length) {
			const price = getPriceFromCells(
				selectedCountryKey,
				productWithSource.sourceCells,
				'cash_price'
			);
			const parsed = Number(price);
			if (!Number.isNaN(parsed)) return parsed;
		}

		const cells = basePriceCells[product.product_code];
		if (cells?.length > 0) {
			const price = getPriceFromCells(selectedCountry.toLowerCase(), cells, 'cash_price');
			const parsed = Number(price);
			if (!Number.isNaN(parsed)) return parsed;
		}

		return null;
	}

	function getCellValue(cells: GristCell[], col: number) {
		return String(cells.find((cell) => cell.coord?.col === col)?.value ?? '');
	}

	function getProductNames(product: PriceSlotProduct) {
		const priceCells = basePriceCells[product.product_code];
		if (priceCells?.length) {
			const englishName = getCellValue(priceCells, 2);
			const localName = getCellValue(priceCells, 3);

			if (englishName) {
				return {
					english: englishName,
					local: localName || englishName
				};
			}
		}

		const [englishName = '', localName = ''] = product.name.split('|').map((name) => name.trim());

		return {
			english: englishName || product.name,
			local: localName || englishName || product.name
		};
	}

	function clonePriceSlot(slot: PriceSlot): PriceSlot {
		return JSON.parse(JSON.stringify(slot));
	}

	function calculateAdjustedPrice(basePrice: number | null): number | null {
		if (basePrice === null) return null;

		const value = Number(adjustmentValue);
		if (Number.isNaN(value)) return basePrice;

		const nextPrice =
			adjustmentMode === 'increase_percent'
				? basePrice * (1 + value / 100)
				: adjustmentMode === 'increase_amount'
					? basePrice + value
					: adjustmentMode === 'decrease_percent'
						? basePrice * (1 - value / 100)
						: basePrice - value;

		return Math.max(0, Math.round(nextPrice));
	}

	function applyCreateTemplate() {
		const value = Number(adjustmentValue);
		const formattedValue = Number.isNaN(value) ? 0 : value;
		const isPercent =
			adjustmentMode === 'increase_percent' || adjustmentMode === 'decrease_percent';
		const isIncrease =
			adjustmentMode === 'increase_percent' || adjustmentMode === 'increase_amount';
		const action = isIncrease ? 'Increase' : 'Decrease';
		const valueLabel = isPercent ? `${formattedValue}%` : `${formattedValue}`;
		const nameSuffix = isPercent ? `${formattedValue}` : `Fixed${formattedValue}`;

		createName = `Profile${action}${nameSuffix}`;
		createDescription = `${isIncrease ? 'increase' : 'decrease'} price ${valueLabel}`;
	}

	function getNextPriceSlotNumber() {
		return Math.max(0, ...displaySlots.map((slot) => slot.slot)) + 1;
	}

	function getCreateSlotNumber() {
		const slotNumber = Number(createSlotNumber);
		if (!Number.isInteger(slotNumber) || slotNumber <= 0) {
			addNotification('WARN:PriceSlot number must be a positive integer');
			return null;
		}

		if (displaySlots.some((slot) => slot.slot === slotNumber)) {
			addNotification(`WARN:PriceSlot${slotNumber} already exists`);
			return null;
		}

		return slotNumber;
	}

	async function openCreateDialog() {
		createSlotNumber = getNextPriceSlotNumber();
		createName = '';
		createDescription = '';

		if (basePriceRowCount > 0) {
			createMode = 'from_price';
			applyCreateTemplate();
			createDialogOpen = true;
			return;
		}

		createMode = 'blank';
		createDialogOpen = true;
	}

	async function ensurePriceBaseRequested() {
		const productCodes = getProductCodesForPriceBase();
		if (productCodes.length > 0) {
			await requestPriceBaseFromProductCodes(productCodes);
			return;
		}

		if (requestedProductCodeCountries.has(selectedCountryKey)) {
			addNotification('INFO:Waiting for product codes before loading Price data');
			return;
		}

		requestedProductCodeCountries.add(selectedCountryKey);
		const sent = await requestListMenu(selectedCountry);
		if (sent) {
			addNotification('INFO:Requesting product codes before loading Price data');
		} else {
			requestedProductCodeCountries.delete(selectedCountryKey);
			pendingCreateDialog = false;
			addNotification('ERR:Failed to request product codes');
		}
	}

	function getProductCodesForPriceBase() {
		const productCodes = new Set<string>();

		if (requestedProductCodeCountries.has(selectedCountryKey)) {
			for (const code of $existingProductCodes) productCodes.add(code);
		}

		for (const product of currentSlot.products) {
			if (product.product_code) productCodes.add(product.product_code);
		}

		if (productCodes.size === 0) {
			for (const slot of backendSlots) {
				for (const product of slot.products) {
					if (product.product_code) productCodes.add(product.product_code);
				}
			}
		}

		return Array.from(productCodes);
	}

	async function requestPriceBaseFromProductCodes(productCodes = getProductCodesForPriceBase()) {
		if (requestedPriceCountries.has(selectedCountryKey)) return;

		if (productCodes.length === 0) return;

		requestedPriceCountries.add(selectedCountryKey);
		const sent = await requestSheetPrice(selectedCountry, productCodes, true);
		if (sent) {
			addNotification(`INFO:Requesting Price data for ${productCodes.length} product codes`);
		} else {
			requestedPriceCountries.delete(selectedCountryKey);
			pendingCreateDialog = false;
			addNotification('ERR:Failed to request Price data');
		}
	}

	function createPriceSlotFromBase() {
		const nextSlotNumber = getCreateSlotNumber();
		if (!nextSlotNumber) return;

		if (createMode === 'blank') {
			const nextSlot: PriceSlot = {
				slot: nextSlotNumber,
				name: createName.trim() || `PriceSlot${nextSlotNumber}`,
				description: createDescription.trim(),
				kind: 'price',
				header: [],
				products: []
			};

			localSlots = [...localSlots, nextSlot];
			selectedSlot = nextSlotNumber;
			workingSlot = clonePriceSlot(nextSlot);
			savedSlot = null;
			lastLoadedSlotSignature = getSlotSignature(nextSlot);
			productPage = 1;
			servicePage = 1;
			createDialogOpen = false;
			addNotification(`INFO:Created blank PriceSlot${nextSlotNumber}`);
			return;
		}

		const baseProducts = getBaseProducts();
		if (baseProducts.length === 0) {
			addNotification('WARN:Main Price data is not ready');
			return;
		}

		const products = baseProducts.map((product) => ({
			...product,
			price: calculateAdjustedPrice(getBasePrice(product))
		}));

		const nextSlot: PriceSlot = {
			slot: nextSlotNumber,
			name: createName.trim() || `PriceSlot${nextSlotNumber}`,
			description: createDescription.trim(),
			kind: 'price',
			header: basePriceHeader,
			products
		};

		localSlots = [...localSlots, nextSlot];
		selectedSlot = nextSlotNumber;
		workingSlot = clonePriceSlot(nextSlot);
		savedSlot = null;
		lastLoadedSlotSignature = getSlotSignature(nextSlot);
		productPage = 1;
		servicePage = 1;
		createDialogOpen = false;
		addNotification(`INFO:Created PriceSlot${nextSlotNumber} from base prices`);
	}

	function countChangedProducts(current: PriceSlot, saved: PriceSlot | undefined): number {
		if (!saved) return 0;

		return current.products.filter((product, index) => {
			if (!product.row_index) return false;
			const savedProduct =
				saved.products.find(
					(item) => product.row_index !== undefined && item.row_index === product.row_index
				) ??
				saved.products[index] ??
				saved.products.find((item) => item.product_code === product.product_code);
			return (
				savedProduct?.product_code !== product.product_code || savedProduct?.price !== product.price
			);
		}).length;
	}

	function countAddedProducts(current: PriceSlot, saved: PriceSlot | undefined): number {
		if (current.kind === 'service') return 0;
		return current.products.filter((product, index) => {
			if (product.row_index) return false;
			const savedProduct = saved?.products[index];
			return (
				!savedProduct ||
				savedProduct.product_code !== product.product_code ||
				savedProduct.price !== product.price
			);
		}).length;
	}

	function countChangedServiceRows(current: PriceSlot, saved: PriceSlot | undefined): number {
		if (!saved || current.kind !== 'service') return 0;

		return (current.serviceRows ?? []).filter((row, index) => {
			const savedRow =
				saved.serviceRows?.find((item) => item.row_index === row.row_index) ??
				saved.serviceRows?.[index];
			return JSON.stringify(row.cells) !== JSON.stringify(savedRow?.cells ?? {});
		}).length;
	}

	function getChangedPriceRows(current: PriceSlot, saved: PriceSlot | undefined) {
		return current.products
			.map((product, index) => {
				if (!product.row_index) return null;

				const savedProduct =
					saved?.products.find(
						(item) => product.row_index !== undefined && item.row_index === product.row_index
					) ??
					saved?.products[index] ??
					saved?.products.find((item) => item.product_code === product.product_code);

				const cells = [];
				if (savedProduct?.product_code !== product.product_code) {
					cells.push({
						value: product.product_code,
						coord: { row: product.row_index, col: 1 }
					});
				}
				if (savedProduct?.price !== product.price) {
					cells.push({
						value: product.price === null ? '' : String(product.price),
						coord: { row: product.row_index, col: 5 }
					});
				}

				if (cells.length === 0) return null;

				return {
					row_index: product.row_index,
					cells
				};
			})
			.filter((row): row is NonNullable<typeof row> => row !== null);
	}

	function getAddedPriceSlotRows(slot: PriceSlot) {
		const draftSlot = {
			...slot,
			products: slot.products.filter((product) => !product.row_index)
		};
		return getCreatePriceSlotRows(draftSlot).map(({ cells }) => ({ cells }));
	}

	function getChangedServiceRows(current: PriceSlot, saved: PriceSlot | undefined) {
		if (current.kind !== 'service') return [];

		return (current.serviceRows ?? [])
			.map((row, index) => {
				const savedRow =
					saved?.serviceRows?.find((item) => item.row_index === row.row_index) ??
					saved?.serviceRows?.[index];
				if (!row.row_index) return null;

				const cells = serviceHeaders
					.map((header, headerIndex) => {
						const value = row.cells[header] ?? '';
						if (value === (savedRow?.cells[header] ?? '')) return null;

						return {
							value,
							coord: { row: row.row_index!, col: headerIndex + 1 }
						};
					})
					.filter((cell): cell is NonNullable<typeof cell> => cell !== null);

				if (cells.length === 0) return null;

				return { row_index: row.row_index, cells };
			})
			.filter((row): row is NonNullable<typeof row> => row !== null);
	}

	function getCreatePriceCellIndex() {
		const priceColumnIndex = getPriceColumnIndex(selectedCountryKey, 'cash_price');
		return priceColumnIndex > 0 ? priceColumnIndex - 1 : 4;
	}

	function getCreatePriceSlotHeader(slot: PriceSlot) {
		const header = Array.from({ length: 26 }, () => '');
		const priceCellIndex = getCreatePriceCellIndex();

		header[0] = 'ProductCode';
		header[1] = 'Name';
		header[priceCellIndex] = basePriceHeader[priceCellIndex] || 'Price';
		header[10] = slot.name;
		header[11] = slot.description;

		return header;
	}

	function getCreatePriceSlotRows(slot: PriceSlot) {
		const header = getCreatePriceSlotHeader(slot);
		const priceCellIndex = getCreatePriceCellIndex();

		return slot.products.map((product, index) => {
			const productWithSource = product as PriceSlotProduct & { sourceCells?: GristCell[] };
			const sourceCells = productWithSource.sourceCells ?? [];
			const cells = Array.from({ length: header.length }, () => '');
			const englishName = getCellValue(sourceCells, 2) || product.name;
			const localName = getCellValue(sourceCells, 3);

			cells[0] = product.product_code;
			cells[1] = englishName;
			cells[2] = localName;
			cells[priceCellIndex] = product.price === null ? '' : String(product.price);

			return {
				header: index === 0 ? header : undefined,
				cells
			};
		});
	}

	function updateSlotField(field: 'name' | 'description', value: string) {
		if (!workingSlot) return;
		workingSlot = { ...workingSlot, [field]: value };
	}

	function updateProductCode(
		targetProduct: PriceSlotProduct,
		fallbackIndex: number,
		value: string
	) {
		if (!workingSlot) return;

		workingSlot = {
			...workingSlot,
			products: workingSlot.products.map((product, index) => {
				const sameProduct =
					targetProduct.row_index !== undefined
						? product.row_index === targetProduct.row_index
						: product === targetProduct || index === fallbackIndex;

				return sameProduct ? { ...product, product_code: value } : product;
			})
		};
	}

	function updateProductPrice(
		targetProduct: PriceSlotProduct,
		fallbackIndex: number,
		value: string
	) {
		const price = value === '' ? null : Number(value);

		if (!workingSlot) return;

		workingSlot = {
			...workingSlot,
			products: workingSlot.products.map((product, index) => {
				const sameProduct =
					targetProduct.row_index !== undefined
						? product.row_index === targetProduct.row_index
						: product === targetProduct || index === fallbackIndex;

				return sameProduct
					? { ...product, price: Number.isNaN(price) ? product.price : price }
					: product;
			})
		};
	}

	function openAddDialog() {
		if (!workingSlot || workingSlot.kind === 'service') return;
		addProductCode = '';
		addProductName = '';
		addProductPrice = '';
		addDialogOpen = true;
	}

	function confirmAddProductRow() {
		if (!workingSlot || workingSlot.kind === 'service') return;

		const code = addProductCode.trim();
		if (!code) {
			addNotification('WARN:Product code is required');
			return;
		}

		const price = addProductPrice === '' ? null : Number(addProductPrice);

		workingSlot = {
			...workingSlot,
			products: [
				...workingSlot.products,
				{
					product_code: code,
					name: addProductName.trim(),
					price: Number.isNaN(price) ? null : price
				}
			]
		};

		productPage = Math.max(1, Math.ceil(workingSlot.products.length / rowsPerPage));
		addDialogOpen = false;
		addNotification(`INFO:Added product code ${code}`);
	}

	function deleteProductRow(targetProduct: PriceSlotProduct, fallbackIndex: number) {
		if (!workingSlot || workingSlot.kind === 'service') return;

		if (targetProduct.row_index) {
			deletedProductRowIds = Array.from(
				new Set([...deletedProductRowIds, targetProduct.row_index])
			);
		}

		workingSlot = {
			...workingSlot,
			products: workingSlot.products.filter((product, index) => {
				const sameProduct =
					targetProduct.row_index !== undefined
						? product.row_index === targetProduct.row_index
						: product === targetProduct || index === fallbackIndex;
				return !sameProduct;
			})
		};
		productPage = Math.min(
			productPage,
			Math.max(1, Math.ceil(workingSlot.products.length / rowsPerPage))
		);
	}

	function updateServiceCell(
		row: PriceSlotServiceRow,
		fallbackIndex: number,
		columnName: string,
		value: string
	) {
		if (!workingSlot) return;

		workingSlot = {
			...workingSlot,
			serviceRows: (workingSlot.serviceRows ?? []).map((serviceRow, index) => {
				const sameRow =
					row.row_index !== undefined
						? serviceRow.row_index === row.row_index
						: serviceRow === row || index === fallbackIndex;
				return sameRow
					? {
							...serviceRow,
							cells: {
								...serviceRow.cells,
								[columnName]: value
							}
						}
					: serviceRow;
			})
		};
	}

	function getServiceColumnClass(columnName: string) {
		const normalized = columnName.toLowerCase();
		if (normalized === 'value') return 'min-w-[320px]';
		if (normalized === 'desc') return 'min-w-[300px]';
		if (normalized === 'l') return 'min-w-[360px]';
		if (normalized.includes('schedule')) return 'min-w-[300px]';
		if (normalized.includes('discount')) return 'min-w-[180px]';
		if (normalized === 'type/key') return 'min-w-[150px]';
		if (normalized === 'servicetype') return 'min-w-[130px]';
		if (normalized === 'daytype') return 'min-w-[130px]';
		if (normalized === 'command') return 'min-w-[130px]';
		if (normalized === 'extendvalue') return 'min-w-[130px]';
		if (normalized === 'time(24 hr)' || normalized === 'time( 24 hr)') return 'min-w-[130px]';
		if (['year', 'month', 'day'].includes(normalized)) return 'min-w-[110px]';
		return 'min-w-[120px]';
	}

	function getServiceInputClass(columnName: string) {
		const normalized = columnName.toLowerCase();
		const textClass = normalized === 'l' || normalized.includes('schedule') ? '' : 'font-mono';
		return ['h-10 w-full min-w-0 text-sm', textClass].filter(Boolean).join(' ');
	}

	function getServiceTableMinWidth() {
		return serviceHeaders.reduce((total, header) => {
			const normalized = header.toLowerCase();
			if (normalized === 'value') return total + 320;
			if (normalized === 'desc') return total + 300;
			if (normalized === 'l') return total + 360;
			if (normalized.includes('schedule')) return total + 300;
			if (normalized.includes('discount')) return total + 180;
			if (['type/key', 'servicetype', 'daytype', 'command', 'extendvalue'].includes(normalized)) {
				return total + 140;
			}
			return total + 120;
		}, 0);
	}

	function resetSlot() {
		if (!savedSlot) return;

		workingSlot = clonePriceSlot(savedSlot);
		deletedProductRowIds = [];
		addNotification(`INFO:Reset PriceSlot${selectedSlot}`);
	}

	async function saveSlot() {
		if (!currentSlot.slot) {
			addNotification('WARN:No PriceSlot selected');
			return;
		}
		if (saveLoading) return;

		const content =
			currentSlot.kind === 'service'
				? getChangedServiceRows(currentSlot, savedSlot ?? undefined)
				: getChangedPriceRows(currentSlot, savedSlot ?? undefined);
		const createContent =
			isLocalSlot && currentSlot.kind !== 'service' ? getCreatePriceSlotRows(currentSlot) : [];
		const addContent =
			!isLocalSlot && currentSlot.kind !== 'service' ? getAddedPriceSlotRows(currentSlot) : [];
		const deleteRowIds = currentSlot.kind !== 'service' ? deletedProductRowIds : [];
		if (
			!isLocalSlot &&
			content.length === 0 &&
			addContent.length === 0 &&
			deleteRowIds.length === 0
		) {
			addNotification('WARN:No row changes to save');
			return;
		}
		if (isLocalSlot && createContent.length === 0) {
			addNotification('WARN:No PriceSlot rows to create');
			return;
		}

		saveLoading = true;
		try {
			const slotSnapshot = clonePriceSlot(currentSlot);
			const updateSent =
				isLocalSlot || content.length === 0
					? true
					: await updatePriceSlot(selectedCountry, slotSnapshot, content);
			const addSent = isLocalSlot
				? await addPriceSlot(selectedCountry, slotSnapshot, createContent)
				: await addPriceSlotRows(selectedCountry, slotSnapshot, addContent);
			const deleteSent = await deletePriceSlotRows(selectedCountry, slotSnapshot, deleteRowIds);

			if (!updateSent || !addSent || !deleteSent) {
				addNotification('ERR:Failed to send PriceSlot update');
				return;
			}

			const savedSlotNumber = selectedSlot;
			savedSlot = clonePriceSlot(currentSlot);
			deletedProductRowIds = [];
			localSlots = localSlots.filter((slot) => slot.slot !== savedSlotNumber);
			requestedSlotKeys.delete(`${selectedCountryKey}:${savedSlotNumber}`);
			selectedSlot = savedSlotNumber;
			addNotification(`INFO:PriceSlot${savedSlotNumber} update sent`);

			const refreshed = await requestPriceSlot(selectedCountry, savedSlotNumber);
			if (!refreshed) {
				addNotification(`WARN:PriceSlot${savedSlotNumber} saved but refresh failed`);
			}
		} catch (error) {
			console.error('[PriceSlot] Failed to save PriceSlot', error);
			addNotification('ERR:Failed to send PriceSlot update');
		} finally {
			saveLoading = false;
		}
	}

	async function loadPriceSlots() {
		localSlots = [];
		workingSlot = null;
		savedSlot = null;
		selectedSlot = 0;
		requestedSlotKeys = new Set<string>();
		pendingCreateDialog = false;
		deletedProductRowIds = [];
		priceSlotsLoading.set(true);
		priceSlotsError.set(null);

		const socket = await waitForAuthenticatedSocket();
		if (!socket) {
			priceSlotsLoading.set(false);
			addNotification('ERR:WebSocket auth not ready');
			return;
		}

		const sent = await requestPriceSlots(selectedCountry);
		if (!sent) {
			priceSlotsLoading.set(false);
			addNotification('ERR:Failed to request PriceSlot data');
		}
	}
</script>

<div class="min-h-screen bg-background">
	<div class="w-full px-6 py-8 lg:px-8">
		<div class="mb-7 flex flex-wrap items-start justify-between gap-5">
			<div class="min-w-0">
				<h1 class="text-4xl leading-tight font-bold tracking-normal">
					PriceSlot [ {selectedCountry.toUpperCase()} ]
				</h1>
				<p class="mt-4 text-muted-foreground">
					Edit sheet PriceSlot names, descriptions, and product prices.
				</p>
			</div>
			<div class="flex flex-wrap items-center gap-3">
				{#if enabledCountries.length > 0}
					<Select.Root
						type="single"
						value={selectedCountry}
						onValueChange={(v) => {
							if (v) {
								selectedCountry = v;
								goto(`/sheet/priceslot/${v}`);
							}
						}}
					>
						<Select.Trigger
							class="h-11 w-40 rounded-lg border-border/80 bg-card/70 px-4 font-semibold"
						>
							{selectedCountry.toUpperCase()}
						</Select.Trigger>
						<Select.Content>
							{#each enabledCountries as country}
								<Select.Item value={country}>
									{country.toUpperCase()}
								</Select.Item>
							{/each}
						</Select.Content>
					</Select.Root>
				{/if}

				<Button
					variant="outline"
					class="h-11 rounded-lg"
					onclick={loadPriceSlots}
					disabled={loading}
				>
					<RefreshCw class="mr-2 h-4 w-4" />
					Refresh
				</Button>
			</div>
		</div>

		<div class="sticky top-0 z-30 mb-5 bg-background/95 pt-2 pb-1 backdrop-blur">
			<div class="mb-4 flex gap-2 overflow-x-auto border-b">
				{#if displaySlots.length > 0}
					{#each displaySlots as slot}
						<button
							class={[
								'min-w-28 border-b-2 px-4 py-3 text-sm font-semibold transition-colors',
								selectedSlot === slot.slot
									? 'border-emerald-500 text-foreground'
									: 'border-transparent text-muted-foreground hover:text-foreground'
							]}
							onclick={() => {
								selectedSlot = slot.slot;
								productPage = 1;
								servicePage = 1;
							}}
						>
							PriceSlot{slot.slot}
						</button>
					{/each}
				{:else}
					<div class="py-3 text-sm text-muted-foreground">
						{loading ? 'Loading PriceSlot data...' : 'No PriceSlot data loaded'}
					</div>
				{/if}
			</div>

			<div class="rounded-lg border border-border/80 bg-card p-4 shadow-sm">
				<div
					class="grid grid-cols-1 items-end gap-4 xl:grid-cols-[180px_minmax(220px,1fr)_minmax(280px,1.25fr)_auto]"
				>
					<div class="flex min-w-0 flex-col justify-end gap-2 pb-1">
						<div class="flex items-center gap-3">
							<h2 class="text-xl font-bold tracking-normal">
								{currentSlot.slot ? `PriceSlot${selectedSlot}` : 'No PriceSlot'}
							</h2>
							<Badge variant={hasChanges ? 'default' : 'secondary'}>
								{hasChanges ? `${totalChangedCount} changes` : 'No changes'}
							</Badge>
						</div>
						<!-- <p class="text-sm text-muted-foreground">Column K/L</p> -->
					</div>

					<div class="space-y-1.5">
						<label class="text-xs font-medium text-muted-foreground" for="priceslot-name"
							>Name</label
						>
						<Input
							id="priceslot-name"
							class="h-10"
							value={currentSlot.name}
							disabled={!currentSlot.slot}
							oninput={(event) => updateSlotField('name', event.currentTarget.value)}
						/>
					</div>

					<div class="space-y-1.5">
						<label class="text-xs font-medium text-muted-foreground" for="priceslot-description">
							Description
						</label>
						<Input
							id="priceslot-description"
							class="h-10"
							value={currentSlot.description}
							disabled={!currentSlot.slot}
							oninput={(event) => updateSlotField('description', event.currentTarget.value)}
						/>
					</div>

					<div class="flex flex-wrap items-end justify-start gap-2 xl:justify-end">
						<div class="flex flex-col gap-1">
							<div class="flex flex-wrap gap-2 xl:justify-end">
								<Button
									class="h-11 rounded-lg"
									onclick={openCreateDialog}
									disabled={createPriceBaseLoading}
								>
									<Calculator class="mr-2 h-4 w-4" />
									{createPriceBaseLoading ? 'Loading Price...' : 'Create PriceSlot'}
								</Button>
								<Button
									class="h-11 rounded-lg px-4"
									onclick={saveSlot}
									disabled={saveLoading || !hasChanges || !currentSlot.slot}
								>
									<Save class="mr-2 h-4 w-4" />
									{saveLoading ? 'Saving...' : 'Save'}
								</Button>
								<Button
									variant="outline"
									class="h-11 rounded-lg px-4"
									onclick={resetSlot}
									disabled={!savedSlot || !hasChanges || !currentSlot.slot}
									title={resetButtonTitle}
								>
									<RotateCcw class="mr-2 h-4 w-4" />
									Reset
								</Button>
							</div>
							<p class="text-right text-xs text-muted-foreground">
								Reset discards unsaved changes for the selected PriceSlot.
							</p>
						</div>
					</div>
				</div>
			</div>

			<div class={['mx-auto mt-4 w-full', isServiceSlot ? 'max-w-none' : 'max-w-6xl']}>
				<div class="flex flex-wrap items-end justify-between gap-3">
					<div class="w-full max-w-sm space-y-2">
						<label class="text-sm font-medium" for="product-code-search">
							{isServiceSlot ? 'Search ServiceType' : 'Search ProductCode'}
						</label>
						<div class="relative">
							<Search
								class="pointer-events-none absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground"
							/>
							<Input
								id="product-code-search"
								class="pl-9 font-mono"
								placeholder={isServiceSlot ? 'Trigger1, Discount, ProductCode' : '12-01-01-0001'}
								value={productCodeSearch}
								oninput={(event) => {
									productCodeSearch = event.currentTarget.value;
									productPage = 1;
									servicePage = 1;
								}}
							/>
						</div>
					</div>
					<div class="flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
						{#if !isServiceSlot && currentSlot.slot}
							<Button variant="outline" size="sm" onclick={openAddDialog}>
								<Plus class="mr-2 h-4 w-4" />
								Add ProductCode
							</Button>
						{/if}
						<span>
							Showing {isServiceSlot ? pagedServiceRows.length : pagedProducts.length} of
							{visibleRowCount} filtered / {totalRowCount}
							{isServiceSlot ? 'service rows' : 'products'}
						</span>
						<Button
							variant="outline"
							size="sm"
							disabled={isServiceSlot ? servicePage <= 1 : productPage <= 1}
							onclick={() => {
								if (isServiceSlot) servicePage = Math.max(1, servicePage - 1);
								else productPage = Math.max(1, productPage - 1);
							}}
						>
							Prev
						</Button>
						<span>
							Page {isServiceSlot ? servicePage : productPage} / {isServiceSlot
								? servicePageCount
								: productPageCount}
						</span>
						<Button
							variant="outline"
							size="sm"
							disabled={isServiceSlot
								? servicePage >= servicePageCount
								: productPage >= productPageCount}
							onclick={() => {
								if (isServiceSlot) servicePage = Math.min(servicePageCount, servicePage + 1);
								else productPage = Math.min(productPageCount, productPage + 1);
							}}
						>
							Next
						</Button>
					</div>
				</div>
			</div>
		</div>

		<div class={['mx-auto w-full', isServiceSlot ? 'max-w-none' : 'max-w-6xl']}>
			{#if loading && displaySlots.length === 0}
				<div class="flex h-48 items-center justify-center rounded-lg border text-muted-foreground">
					Loading PriceSlot data...
				</div>
			{:else if $priceSlotsError}
				<div class="rounded-lg border border-red-300 bg-red-50 p-4 text-sm text-red-700">
					{$priceSlotsError}
				</div>
			{:else if displaySlots.length === 0}
				<div class="flex h-48 items-center justify-center rounded-lg border text-muted-foreground">
					No PriceSlot data from backend.
				</div>
			{:else if currentSlot.slot && !isServiceSlot && currentSlot.products.length === 0}
				<div class="flex h-48 items-center justify-center rounded-lg border text-muted-foreground">
					PriceSlot{currentSlot.slot} data is not loaded yet.
				</div>
			{:else if currentSlot.slot && isServiceSlot && (currentSlot.serviceRows?.length ?? 0) === 0}
				<div class="flex h-48 items-center justify-center rounded-lg border text-muted-foreground">
					PriceSlot{currentSlot.slot} data is not loaded yet.
				</div>
			{:else if isServiceSlot}
				<div class="w-full overflow-x-auto rounded-lg border">
					<Table.Root style={`min-width: ${Math.max(1400, getServiceTableMinWidth())}px`}>
						<Table.Header>
							<Table.Row>
								{#each serviceHeaders as header}
									<Table.Head class={getServiceColumnClass(header)}>{header}</Table.Head>
								{/each}
							</Table.Row>
						</Table.Header>
						<Table.Body>
							{#each pagedServiceRows as row, index (`${row.row_index ?? index}-${index}`)}
								<Table.Row>
									{#each serviceHeaders as header}
										<Table.Cell class={getServiceColumnClass(header)}>
											<Input
												class={getServiceInputClass(header)}
												value={row.cells[header] ?? ''}
												oninput={(event) =>
													updateServiceCell(row, index, header, event.currentTarget.value)}
											/>
										</Table.Cell>
									{/each}
								</Table.Row>
							{/each}
							{#if filteredServiceRows.length === 0}
								<Table.Row>
									<Table.Cell
										colspan={Math.max(serviceHeaders.length, 1)}
										class="h-28 text-center text-muted-foreground"
									>
										No service rows found.
									</Table.Cell>
								</Table.Row>
							{/if}
						</Table.Body>
					</Table.Root>
				</div>
			{:else}
				<div class="w-full overflow-hidden rounded-lg border">
					<Table.Root>
						<Table.Header>
							<Table.Row>
								<Table.Head class="w-[230px]">ProductCode</Table.Head>
								<Table.Head>ProductName [{selectedCountryLanguage}]</Table.Head>
								<Table.Head>ProductNameEng</Table.Head>
								<Table.Head class="w-[150px] text-right">Price</Table.Head>
								<Table.Head class="w-[90px]"></Table.Head>
							</Table.Row>
						</Table.Header>
						<Table.Body>
							{#each pagedProducts as product, index (`${product.product_code}-${product.row_index ?? 'new'}-${index}`)}
								{@const productNames = getProductNames(product)}
								<Table.Row>
									<Table.Cell class="font-mono text-sm font-semibold">
										<Input
											class="font-mono text-sm font-semibold"
											value={product.product_code}
											oninput={(event) =>
												updateProductCode(product, index, event.currentTarget.value)}
										/>
									</Table.Cell>
									<Table.Cell class="min-w-64 font-medium">{productNames.local}</Table.Cell>
									<Table.Cell class="min-w-64 text-muted-foreground"
										>{productNames.english}</Table.Cell
									>
									<Table.Cell>
										<Input
											type="number"
											min="0"
											step="1"
											class="ml-auto w-32 text-right font-semibold"
											value={product.price ?? ''}
											oninput={(event) =>
												updateProductPrice(product, index, event.currentTarget.value)}
										/>
									</Table.Cell>
									<Table.Cell class="text-right">
										<Button
											variant="ghost"
											size="sm"
											class="text-destructive hover:text-destructive"
											onclick={() => deleteProductRow(product, index)}
											aria-label={`Delete ${product.product_code || 'product row'}`}
										>
											<Trash2 class="h-4 w-4" />
										</Button>
									</Table.Cell>
								</Table.Row>
							{/each}
							{#if filteredProducts.length === 0}
								<Table.Row>
									<Table.Cell colspan={5} class="h-28 text-center text-muted-foreground">
										No product code found.
									</Table.Cell>
								</Table.Row>
							{/if}
						</Table.Body>
					</Table.Root>
				</div>
			{/if}
		</div>
	</div>
</div>

<Dialog.Root bind:open={createDialogOpen}>
	<Dialog.Content class="sm:max-w-2xl">
		<Dialog.Header>
			<Dialog.Title>Create PriceSlot</Dialog.Title>
			<Dialog.Description>Choose how to create a new PriceSlot.</Dialog.Description>
		</Dialog.Header>

		<div class="space-y-5">
			<div class="space-y-2">
				<label class="text-sm font-medium" for="create-slot-number">PriceSlot Number</label>
				<Input
					id="create-slot-number"
					type="number"
					min="1"
					step="1"
					value={createSlotNumber}
					oninput={(event) => (createSlotNumber = Number(event.currentTarget.value))}
				/>
				<p class="text-xs text-muted-foreground">
					This creates the Google Sheet/Grist namespace as PriceSlot{createSlotNumber || ''}.
				</p>
			</div>

			<div class="space-y-2">
				<label class="text-sm font-medium" for="create-mode">Create Mode</label>
				<Select.Root
					type="single"
					value={createMode}
					onValueChange={(v) => {
						if (v === 'from_price' || v === 'blank') {
							createMode = v;
							if (v === 'from_price') applyCreateTemplate();
						}
					}}
				>
					<Select.Trigger id="create-mode" class="h-10 rounded-lg">
						{createMode === 'from_price'
							? 'From base Price with adjustment'
							: 'Blank (add manually)'}
					</Select.Trigger>
					<Select.Content>
						<Select.Item value="from_price">From base Price with adjustment</Select.Item>
						<Select.Item value="blank">Blank (add manually)</Select.Item>
					</Select.Content>
				</Select.Root>
			</div>

			{#if createMode === 'from_price'}
				<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
					<div class="space-y-2">
						<label class="text-sm font-medium" for="adjustment-mode">Adjustment Mode</label>
						<Select.Root
							type="single"
							value={adjustmentMode}
							onValueChange={(v) => {
								if (v) adjustmentMode = v as AdjustmentMode;
								applyCreateTemplate();
							}}
						>
							<Select.Trigger id="adjustment-mode" class="h-10 rounded-lg">
								{adjustmentModeLabels[adjustmentMode]}
							</Select.Trigger>
							<Select.Content>
								<Select.Item value="increase_percent">Increase by Percentage (%)</Select.Item>
								<Select.Item value="increase_amount">Increase by Fixed Amount</Select.Item>
								<Select.Item value="decrease_percent">Decrease by Percentage (%)</Select.Item>
								<Select.Item value="decrease_amount">Decrease by Fixed Amount</Select.Item>
							</Select.Content>
						</Select.Root>
					</div>

					<div class="space-y-2">
						<label class="text-sm font-medium" for="adjustment-value">
							Adjustment Value
							{adjustmentMode === 'increase_percent' || adjustmentMode === 'decrease_percent'
								? '(%)'
								: ''}
						</label>
						<Input
							id="adjustment-value"
							type="number"
							min="0"
							step="1"
							value={adjustmentValue}
							oninput={(event) => {
								adjustmentValue = Number(event.currentTarget.value);
								applyCreateTemplate();
							}}
						/>
					</div>
				</div>
			{/if}

			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				<div class="space-y-2">
					<label class="text-sm font-medium" for="create-name">Name</label>
					<Input
						id="create-name"
						value={createName}
						oninput={(event) => (createName = event.currentTarget.value)}
					/>
				</div>

				<div class="space-y-2">
					<label class="text-sm font-medium" for="create-description">Description</label>
					<Input
						id="create-description"
						value={createDescription}
						oninput={(event) => (createDescription = event.currentTarget.value)}
					/>
				</div>
			</div>
		</div>

		<Dialog.Footer>
			<Button variant="outline" onclick={() => (createDialogOpen = false)}>Cancel</Button>
			<Button onclick={createPriceSlotFromBase}>
				<Calculator class="mr-2 h-4 w-4" />
				Confirm Create
			</Button>
		</Dialog.Footer>
	</Dialog.Content>
</Dialog.Root>

<Dialog.Root bind:open={addDialogOpen}>
	<Dialog.Content class="sm:max-w-md">
		<Dialog.Header>
			<Dialog.Title>Add ProductCode</Dialog.Title>
			<Dialog.Description>
				Enter the product code, name, and price for the new row.
			</Dialog.Description>
		</Dialog.Header>

		<div class="space-y-4 py-2">
			<div class="space-y-2">
				<label class="text-sm font-medium" for="add-product-code">Product Code</label>
				<Input
					id="add-product-code"
					class="font-mono"
					placeholder="12-01-01-0001"
					bind:value={addProductCode}
				/>
			</div>

			<div class="space-y-2">
				<label class="text-sm font-medium" for="add-product-name">Product Name</label>
				<Input id="add-product-name" placeholder="Product name" bind:value={addProductName} />
			</div>

			<div class="space-y-2">
				<label class="text-sm font-medium" for="add-product-price">Price</label>
				<Input
					id="add-product-price"
					type="number"
					min="0"
					step="1"
					placeholder="0"
					bind:value={addProductPrice}
				/>
			</div>
		</div>

		<Dialog.Footer>
			<Button variant="outline" onclick={() => (addDialogOpen = false)}>Cancel</Button>
			<Button onclick={confirmAddProductRow}>
				<Plus class="mr-2 h-4 w-4" />
				Add
			</Button>
		</Dialog.Footer>
	</Dialog.Content>
</Dialog.Root>
