'use client';
import { InventoryLotLineResult, InventoryResult } from '@/app/api/inventory';
import { useTranslation } from 'react-i18next';
import SearchBox, { Criterion } from '../SearchBox';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { uniq, uniqBy } from 'lodash';
import InventoryTable from './InventoryTable';
import { defaultPagingController } from '../SearchResults/SearchResults';
import InventoryLotLineTable from './InventoryLotLineTable';
import { useQrCodeScannerContext } from '@/components/QrCodeScannerProvider/QrCodeScannerProvider';
import {
  analyzeQrCode,
  SearchInventory,
  SearchInventoryLotLine,
  fetchInventoriesLatest,
  fetchInventoryLotLines,
} from '@/app/api/inventory/actions';
import { PrinterCombo } from '@/app/api/settings/printer';
import { ItemCombo, fetchItemsWithDetails, ItemWithDetails } from '@/app/api/settings/item/actions';
import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  TextField,
  Box,
  CircularProgress,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  Radio,
} from '@mui/material';

interface Props {
  inventories: InventoryResult[];
  printerCombo?: PrinterCombo[];
}

type SearchQuery = Partial<
  Omit<
    InventoryResult,
    | "id"
    | "qty"
    | "uomCode"
    | "uomUdfudesc"
    | "germPerSmallestUnit"
    | "qtyPerSmallestUnit"
    | "itemSmallestUnit"
    | "price"
    | "description"
    | "category"
  >
>;
type SearchParamNames = keyof SearchQuery;

/** FP-MTMS Version Checklist | Functions Ref. No. 18 | v1.0.0 | 2026-07-17 */
const InventorySearch: React.FC<Props> = ({ inventories, printerCombo }) => {
  const { t } = useTranslation(['inventory', 'common', 'item']);

  const buildSyntheticInventory = useCallback(
    (item: ItemWithDetails): InventoryResult => ({
      id: 0,
      itemId: item.id,
      itemCode: item.code,
      itemName: item.name,
      itemType: 'Material',
      onHandQty: 0,
      onHoldQty: 0,
      unavailableQty: 0,
      availableQty: 0,
      uomCode: item.uom,
      uomUdfudesc: item.uomDesc,
      uomShortDesc: item.uom,
      qtyPerSmallestUnit: 1,
      baseUom: item.uom,
      price: 0,
      currencyName: '',
      status: 'active',
      latestMarketUnitPrice: undefined,
      latestMupUpdatedDate: undefined,
    }),
    [],
  );

  const getFirstItemRecord = useCallback((res: any): ItemWithDetails | null => {
    if (!res) return null;
    if (Array.isArray(res)) return (res[0] as ItemWithDetails) ?? null;
    if (Array.isArray(res?.records)) return (res.records[0] as ItemWithDetails) ?? null;
    return null;
  }, []);


  // Inventory
  const [filteredInventories, setFilteredInventories] = useState<InventoryResult[]>([]);
  const [inventoriesPagingController, setInventoriesPagingController] = useState(defaultPagingController)
  const [inventoriesTotalCount, setInventoriesTotalCount] = useState(0)
  const [selectedInventory, setSelectedInventory] = useState<InventoryResult | null>(null)

  // Inventory Lot Line
  const [filteredInventoryLotLines, setFilteredInventoryLotLines] = useState<InventoryLotLineResult[]>([]);
  const [inventoryLotLinesPagingController, setInventoryLotLinesPagingController] = useState(defaultPagingController)
  const [inventoryLotLinesTotalCount, setInventoryLotLinesTotalCount] = useState(0)

  // Scan-mode UI (hardware QR scanner via QrCodeScannerProvider)
  const qrScanner = useQrCodeScannerContext();
  const [scanUiMode, setScanUiMode] = useState<'idle' | 'scanning'>('idle');
  const [scanHoverCancel, setScanHoverCancel] = useState(false);

  // Resolved lot no for filtering
  const [lotNoFilter, setLotNoFilter] = useState('');
  const [scannedItemId, setScannedItemId] = useState<number | null>(null);

  // Opening inventory (pure opening stock for items without existing inventory)
  const [openingItems, setOpeningItems] = useState<ItemCombo[]>([]);
  const [openingModalOpen, setOpeningModalOpen] = useState(false);
  const [openingSelectedItem, setOpeningSelectedItem] = useState<ItemCombo | null>(null);
  const [openingLoading, setOpeningLoading] = useState(false);
  const [openingSearchText, setOpeningSearchText] = useState('');

  const defaultInputs = useMemo(
    () => ({
      itemId: '',
      itemCode: '',
      itemName: '',
      itemType: '',
      onHandQty: '',
      onHoldQty: '',
      unavailableQty: '',
      availableQty: '',
      currencyName: '',
      status: '',
      baseUom: '',
      uomShortDesc: '',
      latestMarketUnitPrice: '',
      latestMupUpdatedDate: '',
    }),
    [],
  );
  const [inputs, setInputs] = useState<Record<SearchParamNames, string>>(defaultInputs);

  const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
    () => [
      { label: t('Code'), paramName: 'itemCode', type: 'text' },
      { label: t('Name'), paramName: 'itemName', type: 'text' },
      {
        label: t('Type'),
        paramName: 'itemType',
        type: 'select-labelled',
        options: uniq(inventories.map((i) => i.itemType)).map((type) => ({
          value: type,
          label: t(type),
        })),
      },
      // {
      //   label: t("Status"),
      //   paramName: "status",
      //   type: "select",
      //   options: uniq(inventories.map((i) => i.status)),
      // },
    ],
    [t, inventories],
  );

  // Inventory
  const refetchInventoryData = useCallback(
    async (
      query: Record<SearchParamNames, string>,
      actionType: 'reset' | 'search' | 'paging' | 'init',
      pagingController: typeof defaultPagingController,
      lotNo: string,
    ) => {
      console.log('%c Action Type 1.', 'color:red', actionType);
      // Avoid loading data again
      if (actionType === 'paging' && pagingController === defaultPagingController) {
        return;
      }
      console.log('%c Action Type 2.', 'color:blue', actionType);

      const params: SearchInventory = {
        code: query?.itemCode ?? '',
        name: query?.itemName ?? '',
        type: query?.itemType.toLowerCase() === 'all' ? '' : query?.itemType ?? '',
        lotNo: lotNo?.trim() ? lotNo.trim() : undefined,
        pageNum: pagingController.pageNum - 1,
        pageSize: pagingController.pageSize,
      };

      const response = await fetchInventoriesLatest(params);

      if (response) {
        setInventoriesTotalCount(response.total);
        switch (actionType) {
          case 'init':
          case 'reset':
          case 'search':
            setFilteredInventories(() => response.records);
            break;
          case 'paging':
            setFilteredInventories((fi) =>
              uniqBy([...fi, ...response.records], 'itemId'),
            );
        }
      }

      return response;
    },
    [],
  );

  useEffect(() => {
    refetchInventoryData(defaultInputs, 'init', defaultPagingController, '');
  }, [defaultInputs, refetchInventoryData]);

  useEffect(() => {
    // if (!isEqual(inventoriesPagingController, defaultPagingController)) {
      refetchInventoryData(inputs, 'paging', inventoriesPagingController, lotNoFilter)
    // }
  }, [inventoriesPagingController, inputs, lotNoFilter, refetchInventoryData])

  // Inventory Lot Line
  const refetchInventoryLotLineData = useCallback(
    async (
      itemId: number | null,
      actionType: 'reset' | 'search' | 'paging',
      pagingController: typeof defaultPagingController,
    ) => {
      if (!itemId) {
        setSelectedInventory(null);
        setInventoryLotLinesTotalCount(0);
        setFilteredInventoryLotLines([]);
        return;
      }

      // Avoid loading data again
      if (actionType === 'paging' && pagingController === defaultPagingController) {
        return;
      }

      const params: SearchInventoryLotLine = {
        itemId,
        pageNum: pagingController.pageNum - 1,
        pageSize: pagingController.pageSize,
      };

      const response = await fetchInventoryLotLines(params);
      if (response) {
        setInventoryLotLinesTotalCount(response.total);
        switch (actionType) {
          case 'reset':
          case 'search':
            setFilteredInventoryLotLines(() => response.records);
            break;
          case 'paging':
            setFilteredInventoryLotLines((fi) => uniqBy([...fi, ...response.records], 'id'));
        }
      }
    },
    [],
  );

  useEffect(() => {
    // if (!isEqual(inventoryLotLinesPagingController, defaultPagingController)) {
      refetchInventoryLotLineData(selectedInventory?.itemId ?? null, 'paging', inventoryLotLinesPagingController)
    // }
  }, [inventoryLotLinesPagingController])

  // Reset
  const onReset = useCallback(() => {
    refetchInventoryData(defaultInputs, 'reset', defaultPagingController, '');
    refetchInventoryLotLineData(null, 'reset', defaultPagingController);
    // setFilteredInventories(inventories);

    setLotNoFilter('');
    setScannedItemId(null);
    setScanUiMode('idle');
    setScanHoverCancel(false);
    qrScanner.stopScan();
    qrScanner.resetScan();
    setInputs(() => defaultInputs)
    setInventoriesPagingController(() => defaultPagingController)
    setInventoryLotLinesPagingController(() => defaultPagingController)
  }, [defaultInputs, qrScanner, refetchInventoryData, refetchInventoryLotLineData]);

  // Click Row
  const onInventoryRowClick = useCallback(
    (item: InventoryResult) => {
      refetchInventoryLotLineData(item.itemId, 'search', defaultPagingController);
      setSelectedInventory(item);
      setInventoryLotLinesPagingController(() => defaultPagingController);
    },
    [refetchInventoryLotLineData],
  );

  // On Search
  const onSearch = useCallback(
    async (query: Record<SearchParamNames, string>) => {
      setLotNoFilter('');
      setScannedItemId(null);
      setScanUiMode('idle');
      setScanHoverCancel(false);
      qrScanner.stopScan();
      qrScanner.resetScan();
      const invRes = await refetchInventoryData(query, 'search', defaultPagingController, '');
      await refetchInventoryLotLineData(null, 'search', defaultPagingController);

      setInputs(() => query);
      setInventoriesPagingController(() => defaultPagingController);
      setInventoryLotLinesPagingController(() => defaultPagingController);

      // If there are no inventory rows, render a synthetic inventory so the "Stock Adjustment" chip can be used.
      if (invRes?.records?.length === 0) {
        try {
          const code = query.itemCode?.trim?.();
          const name = query.itemName?.trim?.();
          const lookupParams = code ? { code } : name ? { name } : null;

          if (lookupParams) {
            const itemRes = await fetchItemsWithDetails(lookupParams);
            const firstItem = getFirstItemRecord(itemRes);
            if (firstItem) {
              setSelectedInventory(buildSyntheticInventory(firstItem));
              setFilteredInventoryLotLines([]);
              setInventoryLotLinesPagingController(() => defaultPagingController);
            }
          }
        } catch (e) {
          console.error('Failed to build synthetic inventory:', e);
        }
      }
    },
    [
      qrScanner,
      refetchInventoryData,
      refetchInventoryLotLineData,
      buildSyntheticInventory,
      getFirstItemRecord,
    ],
  );

  const startLotScan = useCallback(() => {
    setScanHoverCancel(false);
    setScanUiMode('scanning');
    qrScanner.resetScan();
    qrScanner.startScan();
  }, [qrScanner]);

  const cancelLotScan = useCallback(() => {
    qrScanner.stopScan();
    qrScanner.resetScan();
    setScanUiMode('idle');
    setScanHoverCancel(false);
  }, [qrScanner]);

  useEffect(() => {
    if (scanUiMode !== 'scanning') return;

    const itemId = qrScanner.result?.itemId;
    const stockInLineId = qrScanner.result?.stockInLineId;
    if (!itemId || !stockInLineId) return;

    (async () => {
      try {
        const res = await analyzeQrCode({
          itemId: Number(itemId),
          stockInLineId: Number(stockInLineId),
        });

        const resolvedLotNo = res?.scanned?.lotNo?.trim?.() ? res.scanned.lotNo.trim() : '';
        if (!resolvedLotNo) return;

        setLotNoFilter(resolvedLotNo);
        setScannedItemId(res?.itemId ?? Number(itemId));

        const invRes = await refetchInventoryData(inputs, 'search', defaultPagingController, resolvedLotNo);
        const records = invRes?.records ?? [];
        const target = records.find((r) => r.itemId === (res?.itemId ?? Number(itemId))) ?? null;

        if (target) {
          onInventoryRowClick(target);
        } else {
          refetchInventoryLotLineData(null, 'search', defaultPagingController);
          // No inventory rows for this scanned item => show synthetic inventory with the existing chip workflow.
          const itemRes = await fetchItemsWithDetails({ code: res?.itemCode });
          const firstItem = getFirstItemRecord(itemRes);
          if (firstItem) {
            setSelectedInventory(buildSyntheticInventory(firstItem));
            setFilteredInventoryLotLines([]);
            setInventoryLotLinesPagingController(() => defaultPagingController);
          } else {
            setSelectedInventory(null);
          }
        }

        setInventoriesPagingController(() => defaultPagingController);
        setInventoryLotLinesPagingController(() => defaultPagingController);
      } catch (e) {
        console.error('Failed to analyze QR code:', e);
      } finally {
        // Always go back to initial state after a scan attempt
        cancelLotScan();
      }
    })();
  }, [
    cancelLotScan,
    inputs,
    onInventoryRowClick,
    qrScanner.result,
    refetchInventoryData,
    refetchInventoryLotLineData,
    buildSyntheticInventory,
    getFirstItemRecord,
    scanUiMode,
  ]);

  console.log('', 'color: #666', inventoriesPagingController);

  const handleOpenOpeningInventoryModal = useCallback(() => {
    setOpeningSelectedItem(null);
    setOpeningItems([]);
    setOpeningSearchText('');
    setOpeningModalOpen(true);
  }, []);

  const handleOpeningSearch = useCallback(async () => {
    const trimmed = openingSearchText.trim();
    if (!trimmed) {
      setOpeningItems([]);
      return;
    }

    setOpeningLoading(true);
    try {
      const searchParams: Record<string, any> = {
        pageSize: 50,
        pageNum: 1,
      };

      // Heuristic: if input contains space, treat as name; otherwise treat as code.
      if (trimmed.includes(' ')) {
        searchParams.name = trimmed;
      } else {
        searchParams.code = trimmed;
      }

      const response = await fetchItemsWithDetails(searchParams);

      let records: any[] = [];
      if (response && typeof response === 'object') {
        const anyRes = response as any;
        if (Array.isArray(anyRes.records)) {
          records = anyRes.records;
        } else if (Array.isArray(anyRes)) {
          records = anyRes;
        }
      }

      const combos: ItemCombo[] = records.map((item: any) => ({
        id: item.id,
        label: `${item.code} - ${item.name}`,
        uomId: item.uomId,
        uom: item.uom,
        uomDesc: item.uomDesc,
        group: item.group,
        currentStockBalance: item.currentStockBalance,
      }));

      setOpeningItems(combos);
    } catch (e) {
      console.error('Failed to search items for opening inventory:', e);
      setOpeningItems([]);
    } finally {
      setOpeningLoading(false);
    }
  }, [openingSearchText]);

  const handleConfirmOpeningInventory = useCallback(() => {
    if (!openingSelectedItem) {
      setOpeningModalOpen(false);
      return;
    }

    const rawLabel = openingSelectedItem.label ?? '';
    const [codePart, ...nameParts] = rawLabel.split(' - ');
    const itemCode = codePart?.trim() || rawLabel;
    const itemName = nameParts.join(' - ').trim() || itemCode;

    const syntheticInventory: InventoryResult = {
      id: 0,
      itemId: Number(openingSelectedItem.id),
      itemCode,
      itemName,
      itemType: 'Material',
      onHandQty: 0,
      onHoldQty: 0,
      unavailableQty: 0,
      availableQty: 0,
      uomCode: openingSelectedItem.uom,
      uomUdfudesc: openingSelectedItem.uomDesc,
      uomShortDesc: openingSelectedItem.uom,
      qtyPerSmallestUnit: 1,
      baseUom: openingSelectedItem.uom,
      price: 0,
      currencyName: '',
      status: 'active',
      latestMarketUnitPrice: undefined,
      latestMupUpdatedDate: undefined,
    };

    // Use this synthetic inventory to drive the stock adjustment UI
    setSelectedInventory(syntheticInventory);
    setFilteredInventoryLotLines([]);
    setInventoryLotLinesPagingController(() => defaultPagingController);
    setOpeningModalOpen(false);
  }, [openingSelectedItem]);

  return (
    <>
      <SearchBox
        criteria={searchCriteria}
        onSearch={(query) => {
          onSearch(query);
        }}
        onReset={onReset}
        extraActions={
          <Box sx={{ display: 'flex', gap: 1, alignItems: 'center', flexWrap: 'wrap' }}>
            {scanUiMode === 'idle' ? (
              <Button variant="contained" onClick={startLotScan}>
                {t('Search lot by QR code')}
              </Button>
            ) : (
              <>
                <Button variant="contained" disabled sx={{ bgcolor: 'grey.400', color: 'grey.800' }}>
                  {t('Please scan...')}
                </Button>
                <Button variant="contained" color="error" onClick={cancelLotScan}>
                  {t('Stop QR Scan')}
                </Button>
              </>
            )}

            <Button
              variant="outlined"
              color="secondary"
              onClick={handleOpenOpeningInventoryModal}
              sx={{ display: 'none' }}
            >
              {t('Add entry for items without inventory')}
            </Button>
          </Box>
        }
      />
      <InventoryTable
        inventories={filteredInventories}
        pagingController={inventoriesPagingController}
        setPagingController={setInventoriesPagingController}
        totalCount={inventoriesTotalCount}
        onRowClick={onInventoryRowClick}
      />
      <InventoryLotLineTable
        inventoryLotLines={filteredInventoryLotLines}
        pagingController={inventoryLotLinesPagingController}
        setPagingController={setInventoryLotLinesPagingController}
        totalCount={inventoryLotLinesTotalCount}
        inventory={selectedInventory}
        filterLotNo={lotNoFilter}
        printerCombo={printerCombo ?? []}
        onStockTransferSuccess={() =>
          refetchInventoryLotLineData(
            selectedInventory?.itemId ?? null,
            'search',
            inventoryLotLinesPagingController,
          )
        }
        onStockAdjustmentSuccess={async () => {
          const itemId = selectedInventory?.itemId ?? null;

          // Refresh both blocks:
          // - middle: InventoryTable (inventories list)
          // - bottom: InventoryLotLineTable (lot lines for selected item)
          const invRes = await refetchInventoryData(
            inputs,
            'search',
            inventoriesPagingController,
            lotNoFilter,
          );

          await refetchInventoryLotLineData(
            itemId,
            'search',
            inventoryLotLinesPagingController,
          );

          // If inventory becomes available again after OPEN/ADJ, sync selected row.
          if (itemId != null && invRes?.records?.length) {
            const target = invRes.records.find((r) => r.itemId === itemId);
            if (target) setSelectedInventory(target);
          }
        }}
      />

      <Dialog
        open={openingModalOpen}
        onClose={() => setOpeningModalOpen(false)}
        fullWidth
        maxWidth="md"
      >
        <DialogTitle>{t('Add entry for items without inventory')}</DialogTitle>
        <DialogContent sx={{ pt: 2 }}>
          <Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
            <TextField
              label={t('Item')}
              fullWidth
              value={openingSearchText}
              onChange={(e) => setOpeningSearchText(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  e.preventDefault();
                  handleOpeningSearch();
                }
              }}
              sx={{ flex: 2 }}
            />
            <Button
              variant="contained"
              onClick={handleOpeningSearch}
              disabled={openingLoading}
              sx={{ flex: 1 }}
            >
              {openingLoading ? <CircularProgress size={20} /> : t('common:Search')}
            </Button>
          </Box>

          {openingItems.length === 0 && !openingLoading ? (
            <Box sx={{ py: 1, color: 'text.secondary', fontSize: 14 }}>
              {openingSearchText
                ? t('No data')
                : t('Enter item code or name to search')}
            </Box>
          ) : (
            <Table size="small">
              <TableHead>
                <TableRow>
                  <TableCell />
                  <TableCell>{t('Code')}</TableCell>
                  <TableCell>{t('Name')}</TableCell>
                  <TableCell>{t('UoM')}</TableCell>
                  <TableCell align="right">{t('Current Stock')}</TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {openingItems.map((it) => {
                  const [code, ...nameParts] = (it.label ?? '').split(' - ');
                  const name = nameParts.join(' - ');
                  const selected = openingSelectedItem?.id === it.id;
                  return (
                    <TableRow
                      key={it.id}
                      hover
                      selected={selected}
                      onClick={() => setOpeningSelectedItem(it)}
                      sx={{ cursor: 'pointer' }}
                    >
                      <TableCell padding="checkbox">
                        <Radio checked={selected} />
                      </TableCell>
                      <TableCell>{code}</TableCell>
                      <TableCell>{name}</TableCell>
                      <TableCell>{it.uomDesc || it.uom}</TableCell>
                      <TableCell align="right">
                        {it.currentStockBalance != null ? it.currentStockBalance : '-'}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          )}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setOpeningModalOpen(false)}>
            {t('common:Cancel')}
          </Button>
          <Button
            variant="contained"
            onClick={handleConfirmOpeningInventory}
            disabled={!openingSelectedItem}
          >
            {t('common:Confirm')}
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
};

export default InventorySearch;
