<script lang="ts">
	import Button from '$lib/components/ui/button/button.svelte';
	import Spinner from '$lib/components/ui/spinner/spinner.svelte';
	import * as Dialog from '$lib/components/ui/dialog/index.js';
	import { onMount, onDestroy } from 'svelte';

	import * as adb from '$lib/core/adb/adb';
	import { addNotification } from '$lib/core/stores/noti';
	import { columns, type RecipeOverview } from '../../recipe/overview/columns';
	import {
		materialFromMachineQuery,
		recipeFromMachine,
		recipeFromMachineLoading,
		recipeFromMachineQuery,
		toppingListFromMachineQuery,
		referenceFromPage,
		toppingGroupFromMachineQuery
	} from '$lib/core/stores/recipeStore';
	import DataTable from '../../recipe/overview/data-table.svelte';
	import { handleIncomingMessages } from '$lib/core/handlers/messageHandler';
	import { auth as authStore } from '$lib/core/stores/auth';
	import { machineInfoStore } from '$lib/core/stores/machineInfoStore';
	import { get } from 'svelte/store';
	import {
		AdbDaemonWebUsbDevice,
		AdbDaemonWebUsbDeviceManager
	} from '@yume-chan/adb-daemon-webusb';
	import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
	import { deviceCredentialManager } from '$lib/core/adb/deviceCredManager';
	import { afterNavigate, goto } from '$app/navigation';
	import { env } from '$env/dynamic/public';
	import { adbWriter, isAdbWriterAvailable, sendToAndroid } from '$lib/core/stores/adbWriter';
	import { AdbInstance } from '../../../state.svelte';
	import {
		setOnMenuSavedCallback,
		clearOnMenuSavedCallback,
		clearMenuSaveState
	} from '$lib/core/stores/menuSaveStore';

	const sourceDir = '/sdcard/coffeevending';
	const stagedMenuStorageKey = 'brew.create-menu.drafts.v1';
	const deletedStagedMenuStorageKey = `${stagedMenuStorageKey}.deleted`;
	const stagedMenuAndroidPath = `${sourceDir}/cfg/supra_draft_menus.json`;

	// fetched recipe
	let devRecipe: any | undefined = $state();

	// data to display
	let data: { recipes: RecipeOverview[] } = $state({
		recipes: []
	});

	let brew_status: string = $state('');

	// refresh command
	let refresh_counter: number = $state(0);
	let stagedMenus: any[] = $state([]);
	let brewConfirmOpen = $state(false);
	let pendingBrewMenu: any | null = $state(null);
	let recipeLoading = $state(false);
	let recipeAutoLoadAttempted = $state(false);
	let isAdbConnected = $derived(Boolean(AdbInstance.instance));
	let isAndroidSocketConnected = $derived(Boolean($adbWriter));
	let isRecipeLoaded = $derived(Boolean(devRecipe));

	async function pullTextWithRetry(path: string, timeoutMs = 15000, attempts = 2) {
		for (let attempt = 1; attempt <= attempts; attempt++) {
			const content = await adb.pull(path, timeoutMs);
			if (content != undefined) return content;
			if (attempt < attempts) {
				await new Promise((resolve) => setTimeout(resolve, 500 * attempt));
			}
		}
	}

	async function startFetchRecipeFromMachine() {
		if (recipeLoading) return;

		let instance = adb.getAdbInstance();
		// recipeFromMachineLoading.set(true);
		referenceFromPage.set('brew');
		console.log('check instance', instance);
		if (instance) {
			recipeLoading = true;
			try {
				console.log('instance passed!');
				const recipePaths = [
					`${sourceDir}/cfg/recipe_branch_dev.json`,
					`${sourceDir}/coffeethai02.json`
				];

				for (const recipePath of recipePaths) {
					const dev_recipe = await pullTextWithRetry(recipePath);
					console.log('dev recipe pull result', {
						recipePath,
						loaded: dev_recipe != undefined,
						size: dev_recipe?.length ?? 0
					});
					if (!dev_recipe || dev_recipe.trim().length == 0) continue;

					try {
						devRecipe = JSON.parse(dev_recipe);
						buildOverviewForBrewing();
						return;
					} catch (error) {
						console.error('failed to parse recipe json', recipePath, error);
						addNotification(`ERROR:Invalid recipe JSON from ${recipePath}`);
					}
				}

				addNotification('ERROR:Cannot fetch recipe from machine');
			} finally {
				recipeLoading = false;
			}
		} else {
			addNotification('ERROR:Cannot connect to machine');
			// recipeFromMachineLoading.set(false);
		}
	}

	async function loadEssentialFiles() {
		let instance = adb.getAdbInstance();
		if (instance) {
			// check country
			let country = await adb.pull('/sdcard/coffeevending/country/short');
			// check dev
			let devMode = await adb.pull('/sdcard/coffeevending/CURR_TEST');
			// check .bid
			let boxid = await adb.pull('/sdcard/coffeevending/.bid');

			machineInfoStore.set({
				boxId: boxid,
				versions: {
					firmware: '',
					brew: '',
					xmlengine: '',
					netcore: '',
					devbox: ''
				},
				devMode: devMode?.includes('1') ?? false,
				country: country ?? '',
				status: '',
				errors: []
			});

			handleIncomingMessages(
				JSON.stringify({
					type: 'chat',
					payload: `${new Date().toLocaleTimeString()}: ${get(authStore)?.displayName} has connected to ${boxid}`
				})
			);
		} else {
			addNotification('ERROR:Failed to get machine info');
		}
	}

	async function connectAdb() {
		try {
			if (adb.getAdbInstance()) {
				if (!isAdbWriterAvailable()) {
					await adb.reconnectAndroidServer();
				}
				await loadBrewDataFromConnectedAdb();
				return;
			}

			if (!('usb' in navigator)) {
				throw new Error('WebUSB not supported, try using fallback method or different browser');
			}

			await adb.connnectViaWebUSB();
			let instance = adb.getAdbInstance();

			if (instance) {
				await loadBrewDataFromConnectedAdb();
			}
		} catch (e: any) {
			addNotification(`ERROR:${e}`);
		}
	}

	async function loadBrewDataFromConnectedAdb() {
		await startFetchRecipeFromMachine();
		await loadEssentialFiles();
		await loadStagedMenusFromAndroid();
	}

	async function tryAutoConnect() {
		try {
			if (adb.getAdbInstance()) {
				if (!isAdbWriterAvailable()) {
					await adb.reconnectAndroidServer();
				}
				return true;
			}

			if (!('usb' in navigator) || !AdbDaemonWebUsbDeviceManager.BROWSER) {
				throw new Error('WebUSB not supported, try using fallback method or different browser');
			}

			const devices = await AdbDaemonWebUsbDeviceManager.BROWSER.getDevices();
			if (!devices || devices.length == 0) {
				throw new Error('No device found');
			}

			if (devices.length > 1) {
				throw new Error('Too many connected devices');
			}

			const device = devices[0];
			const credStore = new AdbWebCredentialStore();

			try {
				await adb.connectDeviceByCred(device, credStore);
				return true;
			} catch (e: any) {
				if (e.message === 'CREDENTIAL_EXPIRED') {
					try {
						await deviceCredentialManager.clearAllCredentials();
					} catch (ignored) {}
				}
				if (e instanceof AdbDaemonWebUsbDevice.DeviceBusyError) {
					addNotification(
						'ERR:Device is already in use by another program, please close the program and try again'
					);
				}

				return false;
			}
		} catch (e) {
			console.error('error on auto connect brew page', e);
			addNotification('ERROR:Failed to auto connect, please try again');
		}
	}

	async function ensureAndroidSocket() {
		if (isAdbWriterAvailable()) return true;

		if (!adb.getAdbInstance()) {
			addNotification('ERR:ADB is not connected');
			return false;
		}

		await adb.reconnectAndroidServer();

		if (!isAdbWriterAvailable()) {
			addNotification('ERR:Android socket is not connected');
			return false;
		}

		return true;
	}

	afterNavigate(async () => {
		console.log('after navigate brew');
		await startFetchRecipeFromMachine();
	});

	function getMenuStatus(ms: number): RecipeOverview['status'] {
		switch (ms) {
			case 0:
				return 'ready';
			case 2:
				return 'obsolete';
			case 11:
				return 'pending/online';
			case 12:
				return 'pending/offline';
			default:
				return 'drafted';
		}
	}

	function getMenuCategory(pd: string): string {
		// [country_code]-[category_code]-[drink_Type]-[id]
		let pd_spl = pd.split('-');
		let category = pd_spl[1] ?? '';

		if (category) {
			if (category.endsWith('1')) {
				let result = 'coffee';
				if (category === '01') {
					result += ',v1';
				} else {
					result += ',v2+';
				}

				return result;
			} else if (category.endsWith('2')) {
				return 'tea';
			} else if (category.endsWith('3')) {
				return 'milk';
			} else if (category.endsWith('4')) {
				return 'whey';
			} else if (category.endsWith('5')) {
				return 'soda';
			} else if (category == '99') {
				return 'special';
			}
		}
		return 'unknown';
	}

	function getDrinkType(pd: string): string {
		// [country_code]-[category_code]-[drink_Type]-[id]
		let pd_spl = pd.split('-');
		let drink_type = pd_spl[2] ?? '';

		if (drink_type) {
			if (drink_type.endsWith('1')) {
				return 'hot';
			} else if (drink_type.endsWith('2')) {
				return 'cold / iced';
			} else if (drink_type.endsWith('3')) {
				return 'smoothie / frappe';
			}
		}

		return '';
	}

	// set material used in recipe to tags for using in filter
	function getMainMaterialOfRecipe(rp: any): string {
		let recipeList = rp['recipes'] ?? [];
		let mat_lists = '';

		for (let rpl of recipeList) {
			let mat_id = rpl['materialPathId'];
			let mat_in_use = rpl['isUse'];

			if (mat_in_use && !mat_lists.includes(mat_id)) {
				mat_lists += mat_id + ',';
			}
		}

		mat_lists = mat_lists.substring(0, mat_lists.length - 1);

		return mat_lists;
	}

	function buildTags(rp: any): string {
		let result = '';

		result += getMenuCategory(rp['productCode']);

		let dt = getDrinkType(rp['productCode']);
		let mats = getMainMaterialOfRecipe(rp);

		if (dt !== '') result += ',' + dt;
		if (mats !== '') result += ',' + mats;

		return result;
	}

	function buildOverviewForBrewing() {
		if (devRecipe) {
			let recipe01_query: any = {};
			recipeFromMachine.set(devRecipe);
			data.recipes = [];
			for (let rp of devRecipe['Recipe01']) {
				data.recipes.push({
					productCode: rp['productCode'] ?? '<not set>',
					name: rp['name'] ? rp['name'] : (rp['otherName'] ?? '<not set>'),
					description: rp['desciption']
						? rp['desciption']
						: (rp['otherDescription'] ?? '<not set>'),
					tags: buildTags(rp),
					status: getMenuStatus(rp['MenuStatus'])
				});

				recipe01_query[rp['productCode']] = rp;

				if (rp['SubMenu'] && rp['SubMenu'].length > 0) {
					for (let rps of rp['SubMenu']) {
						data.recipes.push({
							productCode: rps['productCode'] ?? '<not set>',
							name: rps['name'] ? rps['name'] : (rps['otherName'] ?? '<not set>'),
							description: rps['desciption']
								? rps['desciption']
								: (rps['otherDescription'] ?? '<not set>'),
							tags: buildTags(rps),
							status: getMenuStatus(rps['MenuStatus'])
						});

						recipe01_query[rps['productCode']] = rps;
					}
				}
			}

			for (const stagedMenu of stagedMenus) {
				if (!recipe01_query[stagedMenu.productCode]) {
					data.recipes.push({
						productCode: stagedMenu.productCode ?? '<not set>',
						name: stagedMenu.name ? stagedMenu.name : (stagedMenu.otherName ?? '<not set>'),
						description: stagedMenu.Description
							? stagedMenu.Description
							: (stagedMenu.otherDescription ?? '<not set>'),
						tags: buildTags(stagedMenu),
						status: 'drafted'
					});
				}
			}

			let materialFromMachine = devRecipe['MaterialSetting'];

			let currentQuery = get(recipeFromMachineQuery);
			currentQuery = {
				...currentQuery,
				recipe: recipe01_query
			};

			let currentMaterialsQuery = materialFromMachine;
			currentQuery = {
				...currentQuery,
				material: currentMaterialsQuery
			};

			recipeFromMachineQuery.set(currentQuery);
			materialFromMachineQuery.set(currentMaterialsQuery);

			toppingListFromMachineQuery.set(devRecipe['Topping']['ToppingList']);
			toppingGroupFromMachineQuery.set(devRecipe['Topping']['ToppingGroup']);
		}
	}

	function findRecipeByProductCode(productCode: string) {
		if (!devRecipe?.Recipe01) return null;
		for (const recipe of devRecipe.Recipe01) {
			if (recipe?.productCode === productCode) return recipe;
			for (const subMenu of recipe?.SubMenu ?? []) {
				if (subMenu?.productCode === productCode) return subMenu;
			}
		}
		return null;
	}

	function isToppingSlotMaterial(materialId: number) {
		return materialId > 8110 && materialId < 8131;
	}

	function getDeletedStagedMenuCodes() {
		try {
			const stored = localStorage.getItem(deletedStagedMenuStorageKey);
			const parsed = stored ? JSON.parse(stored) : [];
			return new Set(Array.isArray(parsed) ? parsed.map(String) : []);
		} catch (error) {
			return new Set<string>();
		}
	}

	function persistDeletedStagedMenuCodes(codes: Set<string>) {
		localStorage.setItem(deletedStagedMenuStorageKey, JSON.stringify([...codes]));
	}

	function markDeletedStagedMenu(productCode: string) {
		const deletedCodes = getDeletedStagedMenuCodes();
		deletedCodes.add(productCode);
		persistDeletedStagedMenuCodes(deletedCodes);
	}

	function persistStagedMenus() {
		localStorage.setItem(stagedMenuStorageKey, JSON.stringify(stagedMenus));
		void persistStagedMenusToAndroid();
	}

	async function persistStagedMenusToAndroid() {
		if (!adb.getAdbInstance()) return;

		try {
			await adb.push(
				stagedMenuAndroidPath,
				JSON.stringify(
					{
						version: 1,
						updatedAt: new Date().toISOString(),
						menus: stagedMenus
					},
					null,
					2
				)
			);
		} catch (error) {
			console.error('failed to persist staged menus to Android', error);
			addNotification('WARN:Failed to save draft menus to Android');
		}
	}

	async function loadStagedMenusFromAndroid() {
		if (!adb.getAdbInstance()) return false;

		try {
			const content = await adb.pull(stagedMenuAndroidPath, 10000);
			if (!content || content.trim().length === 0) {
				if (stagedMenus.length > 0) {
					await persistStagedMenusToAndroid();
				}
				return false;
			}

			const parsed = JSON.parse(content);
			const menus = Array.isArray(parsed) ? parsed : parsed?.menus;
			if (!Array.isArray(menus)) {
				addNotification('WARN:Android draft menu file has invalid format');
				return false;
			}

			const deletedCodes = getDeletedStagedMenuCodes();
			const filteredMenus = menus.filter((menu) => !deletedCodes.has(String(menu?.productCode)));

			stagedMenus = filteredMenus;
			localStorage.setItem(stagedMenuStorageKey, JSON.stringify(stagedMenus));
			if (filteredMenus.length !== menus.length) {
				await persistStagedMenusToAndroid();
			}
			buildOverviewForBrewing();
			return true;
		} catch (error) {
			console.error('failed to load staged menus from Android', error);
			addNotification('WARN:Failed to load draft menus from Android');
			return false;
		}
	}

	function materialDisplayName(material: any) {
		const thaiName = material?.materialName ?? '';
		const englishName = material?.materialOtherName ?? '';
		if (thaiName && englishName) return `${material.id} - ${thaiName} (${englishName})`;
		return `${material?.id ?? '-'} - ${thaiName || englishName || 'Unnamed material'}`;
	}

	function getMaterial(materialPathId: number | null) {
		if (materialPathId == null) return undefined;
		return (devRecipe?.MaterialSetting ?? []).find(
			(material: any) => Number(material?.id) === Number(materialPathId)
		);
	}

	function toppingGroupDisplayName(group: any) {
		const groupName = group?.otherName || group?.name || 'Unnamed group';
		return `${group?.groupID ?? '-'} - ${groupName}`;
	}

	function toppingListDisplayName(topping: any) {
		const toppingName = topping?.otherName || topping?.name || 'Unnamed topping';
		return `${topping?.id ?? '-'} - ${toppingName}`;
	}

	function getAnyToppingGroup(groupID: number | null) {
		if (groupID == null) return undefined;
		return (devRecipe?.Topping?.ToppingGroup ?? []).find(
			(group: any) => Number(group?.groupID) === Number(groupID)
		);
	}

	function getAnyToppingList(toppingID: number | null) {
		if (toppingID == null) return undefined;
		return (devRecipe?.Topping?.ToppingList ?? []).find(
			(topping: any) => Number(topping?.id) === Number(toppingID)
		);
	}

	async function brewMenuOnAndroid(menu: any) {
		if (!(await ensureAndroidSocket())) return;

		await sendToAndroid({
			type: 'brew_prep',
			payload: {
				start: new Date().toLocaleTimeString()
			}
		});
		await sendToAndroid({
			type: 'brew',
			payload: {
				start: new Date().toLocaleTimeString(),
				target: '-',
				data: menu
			}
		});
		addNotification(`INFO:Brew request sent: ${menu.productCode}`);
	}

	function getRecipeStepValueSummary(step: any) {
		const fields = [
			['powderGram', 'Powder gram'],
			['powderTime', 'Powder time'],
			['syrupGram', 'Syrup gram'],
			['syrupTime', 'Syrup time'],
			['waterCold', 'Water cold'],
			['waterYield', 'Water yield'],
			['stirTime', 'Stir time']
		];

		return fields
			.map(([key, label]) => ({ label, value: Number(step?.[key] ?? 0) }))
			.filter((field) => Number.isFinite(field.value) && field.value !== 0);
	}

	function getPendingBrewMaterials() {
		return (pendingBrewMenu?.recipes ?? [])
			.filter((step: any) => {
				const materialPathId = Number(step?.materialPathId);
				return (
					step?.isUse !== false &&
					Number.isFinite(materialPathId) &&
					!isToppingSlotMaterial(materialPathId)
				);
			})
			.map((step: any, index: number) => {
				const materialPathId = Number(step.materialPathId);
				const material = getMaterial(materialPathId);
				return {
					index: index + 1,
					materialPathId,
					name: material ? materialDisplayName(material) : `${materialPathId} - Unknown material`,
					values: getRecipeStepValueSummary(step)
				};
			});
	}

	function getPendingBrewToppings() {
		return (pendingBrewMenu?.ToppingSet ?? [])
			.map((toppingSet: any, index: number) => {
				const groupID = Number(toppingSet?.groupID);
				const defaultIDSelect = Number(toppingSet?.defaultIDSelect);
				if (
					toppingSet?.isUse === false ||
					!Number.isFinite(groupID) ||
					!Number.isFinite(defaultIDSelect) ||
					defaultIDSelect <= 0
				) {
					return null;
				}

				const group = getAnyToppingGroup(groupID);
				const topping = getAnyToppingList(defaultIDSelect);
				const slotMaterial = getMaterial(8111 + index);

				return {
					slot: index + 1,
					slotName:
						slotMaterial?.materialOtherName ||
						slotMaterial?.materialName ||
						`Topping slot ${index + 1}`,
					groupName: group ? toppingGroupDisplayName(group) : `${groupID} - Unknown group`,
					toppingName: topping
						? toppingListDisplayName(topping)
						: `${defaultIDSelect} - Unknown topping`
				};
			})
			.filter(Boolean);
	}

	function openBrewConfirm(menu: any) {
		pendingBrewMenu = menu;
		brewConfirmOpen = true;
	}

	function promptBrewStagedMenu(menu: any) {
		openBrewConfirm(menu);
	}

	async function confirmBrewNow() {
		if (!pendingBrewMenu) return;
		await brewMenuOnAndroid(pendingBrewMenu);
		brewConfirmOpen = false;
		pendingBrewMenu = null;
	}

	// Track menus pending save verification
	let pendingSaveVerification = $state<Set<string>>(new Set());

	async function verifyMenuSaved(productCode: string, attempt: number = 1): Promise<boolean> {
		const maxAttempts = 3;
		const delayMs = 2000; // 2 seconds between attempts

		if (!adb.getAdbInstance() || recipeLoading) {
			return false;
		}

		await startFetchRecipeFromMachine();

		if (findRecipeByProductCode(productCode)) {
			return true;
		}

		// Retry if not found and attempts remaining
		if (attempt < maxAttempts) {
			addNotification(`INFO:Retry ${attempt}/${maxAttempts} for ${productCode}...`);
			await new Promise((resolve) => setTimeout(resolve, delayMs));
			return verifyMenuSaved(productCode, attempt + 1);
		}

		return false;
	}

	function handleMenuSaved(productCode: string) {
		markDeletedStagedMenu(productCode);
		stagedMenus = stagedMenus.filter((menu) => menu.productCode !== productCode);
		persistStagedMenus();
		clearMenuSaveState(productCode);
		addNotification(`INFO:Menu saved: ${productCode}`);
		buildOverviewForBrewing();
	}

	onMount(() => {
		// Set up callback for when menu is saved to Android
		setOnMenuSavedCallback(handleMenuSaved);

		try {
			const stored = localStorage.getItem(stagedMenuStorageKey);
			stagedMenus = stored ? JSON.parse(stored) : [];
		} catch (error) {
			stagedMenus = [];
		}
		buildOverviewForBrewing();
		if (adb.getAdbInstance()) {
			void loadStagedMenusFromAndroid();
		}
	});

	onDestroy(() => {
		clearOnMenuSavedCallback();
	});

	$effect(() => {
		if (!isAdbConnected) {
			recipeAutoLoadAttempted = false;
			return;
		}

		if (isRecipeLoaded || recipeLoading || recipeAutoLoadAttempted) return;

		recipeAutoLoadAttempted = true;
		void loadBrewDataFromConnectedAdb();
	});

	$effect(() => {
		const brewAppStatusInterval = setInterval(async () => {
			// schedule status from .brew_web_status.log
			let inst = adb.getAdbInstance();
			if (inst && devRecipe && !recipeLoading) {
				await adb.executeCmd(
					'tail -n 1 /sdcard/coffeevending/.brew_web_status.log > /sdcard/coffeevending/.brew_web_status.latest.log'
				);

				const latestStatusPath = env.PUBLIC_BREW_WEB_LATEST_STATUS;
				if (!latestStatusPath) return;

				let brew_status_log = await adb.pull(latestStatusPath);
				if (brew_status_log) {
					let latest_log = brew_status_log;

					if (brew_status !== latest_log) {
						brew_status = latest_log;

						// noti from machine
						if (latest_log.includes('!!!')) {
							let log = latest_log.split('!!!');
							let noti_cfg = log[1];

							if (noti_cfg.includes('=')) {
								let noti_level = noti_cfg.split('=')[1];

								let spl = log[0].split(':');
								let pure_msg = spl[spl.length - 1];

								// case special message
								if (pure_msg.includes('starting retry process')) {
									// is waiting/idle process
									pure_msg = 'Wait for brewing';
								}

								addNotification(`${noti_level}:${pure_msg}`);
							}
						}
					}
				}
			} else if (inst && !devRecipe) {
				// try again
				// await startFetchRecipeFromMachine();
			}
		}, 1000);
		return () => {
			clearInterval(brewAppStatusInterval);
		};
	});
</script>

<div class="mx-8 flex">
	<div class="w-full">
		<div class="mb-4 flex items-center justify-between">
			<div>
				<h1 class="m-8 text-4xl font-bold">Brew</h1>
				<!-- <p class="mx-8 my-0 text-muted-foreground">Brewing directly from web to machine</p>
				<p class="mx-8 my-0 text-muted-foreground">
					Note: refreshing page may cut connection with machine
				</p> -->
			</div>
			<div class="mx-8 my-4 flex gap-2">
				{#if !isAdbConnected}
					<Button variant="default" onclick={() => connectAdb()}>Connect</Button>
				{:else if !isRecipeLoaded}
					<Button
						variant="default"
						onclick={() => loadBrewDataFromConnectedAdb()}
						disabled={recipeLoading}
					>
						{recipeLoading ? 'Loading...' : 'Load Recipes'}
					</Button>
					{#if !isAndroidSocketConnected}
						<Button variant="outline" onclick={() => adb.reconnectAndroidServer()}
							>Reconnect Socket</Button
						>
					{/if}
				{:else}
					<Button variant="default" onclick={() => goto('/tools/create-menu?open=true')}
						>+ Create Menu</Button
					>
				{/if}
			</div>

			<!-- <DashboardQuickAdb enableComponent={true} /> -->
		</div>

		<!-- search bar -->

		{#key refresh_counter}
			<div class="w-full">
				{#if $recipeFromMachineLoading}
					<div class="flex items-center justify-center">
						<p class="mx-4">Please wait</p>
						<Spinner />
					</div>
				{:else}
					<DataTable data={data.recipes} refPage="brew" {columns} />
				{/if}
			</div>
		{/key}
	</div>
</div>

<Dialog.Root bind:open={brewConfirmOpen}>
	<Dialog.Content class="max-h-[90vh] overflow-y-auto sm:max-w-2xl">
		<Dialog.Header>
			<Dialog.Title>Confirm Brew</Dialog.Title>
			<Dialog.Description>
				Check the material and topping list before sending this menu to Android.
			</Dialog.Description>
		</Dialog.Header>

		{#if pendingBrewMenu}
			<div class="grid gap-4 py-2">
				<div class="rounded-md border bg-muted/20 p-4">
					<div class="text-sm text-muted-foreground">Menu</div>
					<div class="mt-1 text-lg font-semibold">
						{pendingBrewMenu.name || pendingBrewMenu.otherName || pendingBrewMenu.productCode}
					</div>
					<div class="mt-1 font-mono text-sm text-muted-foreground">
						{pendingBrewMenu.productCode}
					</div>
				</div>

				<div class="rounded-md border p-4">
					<div class="mb-3 flex items-center justify-between gap-3">
						<h3 class="text-base font-semibold">Materials</h3>
						<span class="rounded-full bg-muted px-2.5 py-1 text-xs text-muted-foreground">
							{getPendingBrewMaterials().length} items
						</span>
					</div>

					<div class="grid gap-2">
						{#each getPendingBrewMaterials() as material}
							<div class="rounded-md border bg-background/70 p-3">
								<div class="flex items-start justify-between gap-3">
									<div>
										<div class="text-xs text-muted-foreground">Step {material.index}</div>
										<div class="font-medium">{material.name}</div>
									</div>
									<div class="font-mono text-xs text-muted-foreground">
										{material.materialPathId}
									</div>
								</div>

								{#if material.values.length > 0}
									<div class="mt-3 flex flex-wrap gap-2">
										{#each material.values as field}
											<span
												class="rounded-full bg-emerald-500 px-2.5 py-1 font-mono text-xs font-semibold text-white"
											>
												{field.label}: {field.value}
											</span>
										{/each}
									</div>
								{:else}
									<div class="mt-3 text-sm text-muted-foreground">No amount values set</div>
								{/if}
							</div>
						{/each}
					</div>
				</div>

				<div class="rounded-md border p-4">
					<div class="mb-3 flex items-center justify-between gap-3">
						<h3 class="text-base font-semibold">Toppings</h3>
						<span class="rounded-full bg-muted px-2.5 py-1 text-xs text-muted-foreground">
							{getPendingBrewToppings().length} items
						</span>
					</div>

					{#if getPendingBrewToppings().length === 0}
						<div class="rounded-md border border-dashed p-3 text-sm text-muted-foreground">
							No toppings selected.
						</div>
					{:else}
						<div class="grid gap-2">
							{#each getPendingBrewToppings() as topping}
								<div class="rounded-md border bg-background/70 p-3">
									<div class="text-xs text-muted-foreground">
										Slot {topping.slot}: {topping.slotName}
									</div>
									<div class="mt-1 font-medium">{topping.toppingName}</div>
									<div class="mt-1 text-sm text-muted-foreground">{topping.groupName}</div>
								</div>
							{/each}
						</div>
					{/if}
				</div>
			</div>
		{/if}

		<Dialog.Footer>
			<Button
				variant="outline"
				onclick={() => {
					brewConfirmOpen = false;
					pendingBrewMenu = null;
				}}
			>
				Cancel
			</Button>
			<Button onclick={confirmBrewNow} disabled={!pendingBrewMenu}>Confirm Brew</Button>
		</Dialog.Footer>
	</Dialog.Content>
</Dialog.Root>
