"use client";

import { DoResult } from "@/app/api/do";
import { DoSearchAll, fetchDoSearch, releaseDo ,startBatchReleaseAsync, getBatchReleaseProgress} from "@/app/api/do/actions";
import { useRouter } from "next/navigation";
import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Criterion } from "../SearchBox";
import { isEmpty, sortBy, uniqBy, upperFirst } from "lodash";
import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil";
import SearchBox from "../SearchBox/SearchBox";
import { EditNote } from "@mui/icons-material";
import InputDataGrid from "../InputDataGrid";
import { CreateConsoDoInput } from "@/app/api/do/actions";
import { TableRow } from "../InputDataGrid/InputDataGrid";
import {
  FooterPropsOverrides,
  GridColDef,
  GridRowModel,
  GridToolbarContainer,
  useGridApiRef,
} from "@mui/x-data-grid";
import {
  FormProvider,
  SubmitErrorHandler,
  SubmitHandler,
  useForm,
} from "react-hook-form"; 
import { Box, Button, Grid, Stack, Typography, TablePagination} from "@mui/material";
import StyledDataGrid from "../StyledDataGrid";
import { GridRowSelectionModel } from "@mui/x-data-grid";
import Swal from "sweetalert2";
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";

type Props = {
  filterArgs?: Record<string, any>;
  searchQuery?: Record<string, any>;
  onDeliveryOrderSearch: () => void;
};
type SearchBoxInputs = Record<"code" | "status" | "estimatedArrivalDate" | "orderDate" | "supplierName" | "shopName" | "deliveryOrderLines" | "codeTo" | "statusTo" | "estimatedArrivalDateTo" | "orderDateTo" | "supplierNameTo" | "shopNameTo" | "deliveryOrderLinesTo" , string>;
type SearchParamNames = keyof SearchBoxInputs;

// put all this into a new component
// ConsoDoForm
type EntryError =
  | {
      [field in keyof DoResult]?: string;
    }
  | undefined;
type DoRow = TableRow<Partial<DoResult>, EntryError>;


const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSearch}) => {
  const apiRef = useGridApiRef();

  const formProps = useForm<CreateConsoDoInput>({
    defaultValues: {},
  });
  const errors = formProps.formState.errors;

  
  const { t } = useTranslation("do");
  const router = useRouter();
  const { data: session } = useSession() as { data: SessionWithTokens | null };
  const currentUserId = session?.id ? parseInt(session.id) : undefined;
  console.log("🔍 DoSearch - session:", session);
  console.log("🔍 DoSearch - currentUserId:", currentUserId);
  const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
  const [rowSelectionModel, setRowSelectionModel] =
    useState<GridRowSelectionModel>([]);

  const [searchAllDos, setSearchAllDos] = useState<DoSearchAll[]>([]);

  const [pagingController, setPagingController] = useState({
    pageNum: 1,
    pageSize: 10,
  });

  const handlePageChange = useCallback((event: unknown, newPage: number) => {
    const newPagingController = {
      ...pagingController,
      pageNum: newPage + 1,
    };
    setPagingController(newPagingController);
  },[pagingController]);

  const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
    const newPageSize = parseInt(event.target.value, 10);
    const newPagingController = {
      pageNum: 1,
      pageSize: newPageSize,
    };
    setPagingController(newPagingController);
  }, []);

  const pagedRows = useMemo(() => {
  const start = (pagingController.pageNum - 1) * pagingController.pageSize;
  return searchAllDos.slice(start, start + pagingController.pageSize);
  }, [searchAllDos, pagingController]);

  const [currentSearchParams, setCurrentSearchParams] = useState<SearchBoxInputs>({
    code: "",
    status: "",
    estimatedArrivalDate: "",
    orderDate: "",
    supplierName: "",
    shopName: "",
    deliveryOrderLines: "",
    codeTo: "",
    statusTo: "",
    estimatedArrivalDateTo: "",
    orderDateTo: "",
    supplierNameTo: "",
    shopNameTo: "",
    deliveryOrderLinesTo: ""
  });

  const [hasSearched, setHasSearched] = useState(false);
  const [hasResults, setHasResults] = useState(false);

  useEffect(() =>{
    setPagingController(p => ({
      ...p,
      pageNum: 1,
    }));
  }, [searchAllDos]);


  const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
    () => [
      { label: t("Code"), paramName: "code", type: "text" },
/*
      {
        label: t("Order Date From"),
        label2: t("Order Date To"),
        paramName: "orderDate",
        type: "dateRange",
      },
      */
      { label: t("Shop Name"), paramName: "shopName", type: "text" },

      {
        label: t("Estimated Arrival"),
        //label2: t("Estimated Arrival To"),
        paramName: "estimatedArrivalDate",
        type: "date",
      },

      {
        label: t("Status"),
        paramName: "status",
        type: "autocomplete",
        options:[
          {label: t('Pending'), value: 'pending'},
          {label: t('Receiving'), value: 'receiving'},
          {label: t('Completed'), value: 'completed'}
        ]
      }
    ],
    [t],
  );

  const onReset = useCallback(async () => {
    try {
      setSearchAllDos([]);
      setHasSearched(false);
      setHasResults(false);
    } 
    catch (error) {
      console.error("Error: ", error);
      setSearchAllDos([]);
  }
  }, []);

  const onDetailClick = useCallback(
    (doResult: DoResult) => {
      router.push(`/do/edit?id=${doResult.id}`);
    },
    [router],
  );

  const validationTest = useCallback(
    (
      newRow: GridRowModel<DoRow>,
      //   rowModel: GridRowSelectionModel
    ): EntryError => {
      const error: EntryError = {};
      console.log(newRow);
      //   if (!newRow.lowerLimit) {
      //     error["lowerLimit"] = "lower limit cannot be null"
      //   }
      //   if (newRow.lowerLimit && newRow.upperLimit && newRow.lowerLimit > newRow.upperLimit) {
      //     error["lowerLimit"] = "lower limit should not be greater than upper limit"
      //     error["upperLimit"] = "lower limit should not be greater than upper limit"
      //   }
      return Object.keys(error).length > 0 ? error : undefined;
    },
    [],
  );

  const columns = useMemo<GridColDef[]>(
    () => [
      // {
      //     name: "id",
      //     label: t("Details"),
      //     onClick: onDetailClick,
      //     buttonIcon: <EditNote />,
      // },
      {
        field: "id",
        headerName: t("Details"),
        width: 100,
        renderCell: (params) => (
          <Button
            variant="outlined"
            size="small"
            startIcon={<EditNote />}
            onClick={() => onDetailClick(params.row)}
          >
            {t("Details")}
          </Button>
        ),
      },
      {
        field: "code",
        headerName: t("code"),
        flex: 1.5,
      },
      {
        field: "shopName",
        headerName: t("Shop Name"),
        flex: 1,
      },
      {
        field: "supplierName",
        headerName: t("Supplier Name"),
        flex: 1,
      },
      
      {
        field: "orderDate",
        headerName: t("Order Date"),
        flex: 1,
        renderCell: (params) => {
          return params.row.orderDate
            ? arrayToDateString(params.row.orderDate)
            : "N/A";
        },
        
      },
      
      {
        field: "estimatedArrivalDate",
        headerName: t("Estimated Arrival"),
        flex: 1,
        renderCell: (params) => {
          return params.row.estimatedArrivalDate
            ? arrayToDateString(params.row.estimatedArrivalDate)
            : "N/A";
        },
      },
      {
        field: "status",
        headerName: t("Status"),
        flex: 1,
        renderCell: (params) => {
          return t(upperFirst(params.row.status));
        },
      },
    ],
    [t, arrayToDateString],
  );

  const onSubmit = useCallback<SubmitHandler<CreateConsoDoInput>>(
    async (data, event) => {
      const hasErrors = false;
      console.log(errors);
    },
    [],
  );
  const onSubmitError = useCallback<SubmitErrorHandler<CreateConsoDoInput>>(
    (errors) => {},
    [],
  );
  //SEARCH FUNCTION
  const handleSearch = useCallback(async (query: SearchBoxInputs) => {
    try {
      setCurrentSearchParams(query);
  
      let orderStartDate = "";
      let orderEndDate = "";
      let estArrStartDate = query.estimatedArrivalDate;
      let estArrEndDate = query.estimatedArrivalDate;
      const time = "T00:00:00";
  
      //if(orderStartDate != ""){
      //  orderStartDate = query.orderDate + time;
      //}
      //if(orderEndDate != ""){
      //  orderEndDate = query.orderDateTo + time;
      //}
      if(estArrStartDate != ""){
        estArrStartDate = query.estimatedArrivalDate + time;
      }
      if(estArrEndDate != ""){
        estArrEndDate = query.estimatedArrivalDate + time;
      }
      
      let status = "";
      if(query.status == "All"){
        status = "";
      }
      else{
        status = query.status;
      }
      
      const data = await fetchDoSearch(
        query.code || "",
        query.shopName || "",
        status,
        orderStartDate,
        orderEndDate,
        estArrStartDate,
        estArrEndDate
      );
  
      setSearchAllDos(data);
      setHasSearched(true);
      setHasResults(data.length > 0);
    } catch (error) {
      console.error("Error: ", error);
      setSearchAllDos([]);
      setHasSearched(true);
      setHasResults(false);
    }
  }, []);
  const debouncedSearch = useCallback((query: SearchBoxInputs) => {
    if (searchTimeout) {
      clearTimeout(searchTimeout);
    }
    
    const timeout = setTimeout(() => {
      handleSearch(query);
    }, 300);
    
    setSearchTimeout(timeout);
  }, [handleSearch, searchTimeout]);

  const handleBatchRelease = useCallback(async () => {
  
    const totalDeliveryOrderLines = searchAllDos.reduce((sum, doItem) => {
      return sum + (doItem.deliveryOrderLines?.length || 0);
    }, 0);

    const result = await Swal.fire({
      icon: "question",
      title: t("Batch Release"),
      html: `
        <div>
          <p>${t("Selected Shop(s): ")}${searchAllDos.length}</p>
          <p>${t("Selected Item(s): ")}${totalDeliveryOrderLines}</p>
        </div>
      `,
      showCancelButton: true,
      confirmButtonText: t("Confirm"),
      cancelButtonText: t("Cancel"),
      confirmButtonColor: "#8dba00",
      cancelButtonColor: "#F04438"
    });
  
    if (result.isConfirmed) {
      const idsToRelease = searchAllDos.map(d => d.id);

    try {
      const startRes = await startBatchReleaseAsync({ ids: idsToRelease, userId: currentUserId ?? 1 });
      const jobId = startRes?.entity?.jobId;
  
      if (!jobId) {
        await Swal.fire({ icon: "error", title: t("Error"), text: t("Failed to start batch release") });
        return;
      }


      const progressSwal = Swal.fire({
          title: t("Releasing"),
          text: "0% (0 / 0)",
          allowOutsideClick: false,
          allowEscapeKey: false,
          showConfirmButton: false,
          didOpen: () => {
            Swal.showLoading();
          }
        });
        
      const timer = setInterval(async () => {
        try {
          const p = await getBatchReleaseProgress(jobId);
          
          const e = p?.entity || {};
          const total = e.total ?? 0;
          const finished = e.finished ?? 0;
          const percentage = total > 0 ? Math.round((finished / total) * 100) : 0;
        
        const textContent = document.querySelector('.swal2-html-container');
        if (textContent) {
          textContent.textContent = `${percentage}% (${finished} / ${total})`;
        }

        if (p.code === "FINISHED" || e.running === false) {
          clearInterval(timer);
          await new Promise(resolve => setTimeout(resolve, 500));
          Swal.close();
        
          await Swal.fire({
            icon: "success",
            title: t("Completed"),
            text: t("Batch release completed successfully."),
            confirmButtonText: t("Confirm"),
            confirmButtonColor: "#8dba00"
          });
        
          if (currentSearchParams && Object.keys(currentSearchParams).length > 0) {
            await handleSearch(currentSearchParams);
          }
        }
      } catch (err) {
        console.error("progress poll error:", err);
      }
    }, 800);
  } catch (error) {
    console.error("Batch release error:", error);
    await Swal.fire({
      icon: "error",
      title: t("Error"),
      text: t("An error occurred during batch release"),
      confirmButtonText: t("OK")
    });
  }}
}, [t, currentUserId, searchAllDos, currentSearchParams, handleSearch]);


  return (
    <>
      <FormProvider {...formProps}>
        <Stack
          spacing={2}
          component="form"
          onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
        >
          <Grid container>
            <Grid item xs={8}>
              <Typography variant="h4" marginInlineEnd={2}>
                {t("Delivery Order")}
              </Typography>
            </Grid>
            <Grid
              item
              xs={4}
              display="flex"
              justifyContent="end"
              alignItems="end"
            >
            <Stack spacing={2} direction="row">
              {/*<Button
                name="submit"
                variant="contained"
                //   startIcon={<Check />}
                type="submit"
              >
                {t("Create")}
              </Button>*/}
              {hasSearched && hasResults && (
                <Button
                  name="batch_release"
                  variant="contained"
                  onClick={handleBatchRelease}
                >
                  {t("Batch Release")}
                </Button>
              )}

            </Stack>
              
            </Grid>
          </Grid>

          <SearchBox
            criteria={searchCriteria}

            onSearch={handleSearch}

            onReset={onReset}
          />

          <StyledDataGrid
            rows={pagedRows}
            columns={columns}
            checkboxSelection
            rowSelectionModel={rowSelectionModel}
            onRowSelectionModelChange={(newRowSelectionModel) => {
              setRowSelectionModel(newRowSelectionModel);
              formProps.setValue("ids", newRowSelectionModel);
            }}
            slots={{
              footer: FooterToolbar,
              noRowsOverlay: NoRowsOverlay,
            }}
          />
          
          <TablePagination
          component="div"
          count={searchAllDos.length}
          page={(pagingController.pageNum - 1)}
          rowsPerPage={pagingController.pageSize}
          onPageChange={handlePageChange}
          onRowsPerPageChange={handlePageSizeChange}
          rowsPerPageOptions={[10, 25, 50]}
        />

        </Stack>

      </FormProvider>
    </>
  );
};


const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
  return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
};
const NoRowsOverlay: React.FC = () => {
  const { t } = useTranslation("home");
  return (
    <Box
      display="flex"
      justifyContent="center"
      alignItems="center"
      height="100%"
    >
      <Typography variant="caption">{t("Add some entries!")}</Typography>
    </Box>
  );
};

export default DoSearch;