"use client";
import { ProjectExpensesResult, ProjectExpensesResultFormatted } from "@/app/api/projectExpenses";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import SearchBox, { Criterion } from "../SearchBox";
import SearchResults, { Column } from "../SearchResults";
import { useRouter } from "next/navigation";
import {
  Button,
  ButtonGroup,
  Card,
  CardContent,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Divider,
  Grid,
  Stack,
  TextField,
  Typography,
} from "@mui/material";
import { INPUT_DATE_FORMAT, moneyFormatter } from "@/app/utils/formatUtil";
import { EditNote } from "@mui/icons-material";
import AddIcon from '@mui/icons-material/Add';
import { uniq } from "lodash";
import CreateExpenseModal from "./CreateExpenseModal";
import { ProjectResult } from "@/app/api/projects";
import StyledDataGrid from "../StyledDataGrid";
import { GridCellParams, GridColDef, GridRenderEditCellParams, GridRowId, GridRowModes, GridRowModesModel, GridValueFormatterParams } from "@mui/x-data-grid";
import { useGridApiRef } from "@mui/x-data-grid";
import { GridEventListener } from "@mui/x-data-grid";
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
import { deleteProjectExpense, updateProjectExpense } from "@/app/api/projectExpenses/actions";
import dayjs from "dayjs";
import React from "react";
import { NumberFormatValues, NumericFormat } from "react-number-format";

interface CustomMoneyComponentProps {
  params: GridRenderEditCellParams;
}

interface Props {
  expenses: ProjectExpensesResultFormatted[]
  projects: ProjectResult[];
}

type SearchQuery = Partial<Omit<ProjectExpensesResultFormatted, "id">>;
type SearchParamNames = keyof SearchQuery;

type Modals = {
  createInvoiceModal: boolean
}
const initState: Modals = { 
  createInvoiceModal: false,
}

type expenseRow = Partial<
  ProjectExpensesResultFormatted & {
    _error: ExpenseRowError;
    issuedDate: Date
  }
>

type ExpenseRowError = {
  [field in keyof ProjectExpensesResultFormatted]?: string
}& {
  message?: string
}

const ExpenseSearch: React.FC<Props> = ({ expenses, projects }) => {
  const router = useRouter();
  const { t } = useTranslation("expenses");
  const [filteredExpenses, setFilteredExpenses] = useState(expenses);
  const [modalsOpen, setModalsOpen] = useState(initState)
  const toggleModals = useCallback((key: keyof Modals) => {
    setModalsOpen((prev) => ({...prev, [key]: !prev[key]}))
  }, [modalsOpen]);

  const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
    () => [
      // { label: t("Expense No"), paramName: "ExpenseNo", type: "text" },
      { label: t("Project Code"), paramName: "projectCode", type: "text" },
      { label: t("Project Name"), paramName: "projectName", type: "text" },
      {
        label: t("Team"),
        paramName: "team",
        type: "select",
        options: uniq(expenses.map((expenses) => `${expenses.teamCode} - ${expenses.teamName}`)),
      },
    ],
    []
  );



  const columns = useMemo<Column<ProjectExpensesResultFormatted>[]>(
    () => [
      {
        name: "id",
        label: t("Details"),
        onClick: (row: ProjectExpensesResultFormatted) => (
          handleButtonClick(row)
        ),
        buttonIcon: <EditNote />,
        // disabled: !abilities.includes(MAINTAIN_PROJECT),
      },
      { name: "expenseNo", label: t("Expense No.")},
      { name: "projectCode", label: t("Project Code") },
      { name: "projectName", label: t("Project Name") },
      { name: "amount", label: t("Amount (HKD)"), type: 'money', needTranslation: true},
      { name: "team", label: t("Team") },
      { name: "issueDate", label: t("Issue Date") },
      { name: "remarks", label: t("Remarks")}
    ],
    [t]
  );
  const onReset = useCallback(() => {
    setFilteredExpenses(expenses);
  }, []);

  /**
   * Edit Dialog
   */
  const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
  const apiRef = useGridApiRef();
  const [selectedRow, setSelectedRow] = useState<expenseRow[] | []>([]);
  const [dialogOpen, setDialogOpen] = useState(false);

  const handleButtonClick = (row: ProjectExpensesResultFormatted) => {
    setSelectedRow([row])
    setDialogOpen(true)
    setRowModesModel((model) => ({
      ...model,
      [row.id]: {mode: GridRowModes.Edit, fieldToFocus: "amount"}
    }))
  }

  const handleCloseDialog = () => {
    setDialogOpen(false);
  };

  const handleDeleteExpense = useCallback(() => {
    deleteDialog(async() => {
      //console.log(selectedRow[0])
      await deleteProjectExpense(selectedRow[0].id!!)
      setDialogOpen(false);
      const result = await successDialog("Delete Success", t);
      if (result) {
        window.location.reload()
      }
    }, t)
  }, [selectedRow]);


  const handleSaveDialog = async () => {
    // setDialogOpen(false);
    // console.log(selectedRow[0]) 
    selectedRow[0].issueDate = dayjs(selectedRow[0].issuedDate).format(INPUT_DATE_FORMAT)
    // console.log(selectedRow[0]) 
    await updateProjectExpense(selectedRow[0])
    setDialogOpen(false);
    successDialog(t("Update Success"), t).then(() => {
      window.location.reload()
    })

    // console.log(selectedRow[0])
    // setSelectedRow([]);
  };

  const validateExpenseEntry = (
    entry: Partial<ProjectExpensesResultFormatted>,
  ): ExpenseRowError | undefined => {
    // Test for errors
    const error: ExpenseRowError = {};
  
    // console.log(entry)
    if (!entry.amount) {
      error.amount = "Please input amount ";
    }

  
    return Object.keys(error).length > 0 ? error : undefined;
  }

  const validateRow = useCallback(
    (id: GridRowId) => {
      const row = apiRef.current.getRowWithUpdatedValues(
        id,
        "",
      )

      const error = validateExpenseEntry(row);
      console.log(error)
      // Test for warnings

      apiRef.current.updateRows([{ id, _error: error }]);
      return !error;
    },
    [apiRef],
  );

  const handleEditStop = useCallback<GridEventListener<"rowEditStop">>(
    (params, event) => {
      // console.log(params.id)
      if (validateRow(params.id) !== undefined || !validateRow(params.id)) {
        
        setRowModesModel((model) => ({
          ...model,
          [params.id]: { mode: GridRowModes.View},
        }));
        
        const row = apiRef.current.getRowWithUpdatedValues(
          params.id,
          "",
        )
        console.log(row)
        setSelectedRow([{...row}] as ProjectExpensesResultFormatted[])
        event.defaultMuiPrevented = true;
      }
      // console.log(row)
    },
    [validateRow],
  );

  // Money format : 000,000,000.00
  const CustomMoneyFormat = useCallback((value: number) => {
    if (value) {
      return moneyFormatter.format(value);
    } else {
      return ""
    }
}, [])

const CustomMoneyComponent: React.FC<CustomMoneyComponentProps> = ({ params }) => {
  const { id, value, field } = params;
  const ref = React.useRef();

  const handleValueChange = (newValue: NumberFormatValues) => {
    apiRef.current.setEditCellValue({ id, field, value: newValue.value });
  };

  return <NumericFormat
    fullWidth
    prefix="HK$"
    onValueChange={(values) => {
      console.log(values)
      handleValueChange(values)
    }}
    customInput={TextField}
    thousandSeparator
    valueIsNumericString
    decimalScale={2}
    fixedDecimalScale
    value={value}
    inputRef={ref}
    InputProps={{
      sx: {
        '& .MuiInputBase-input': {
          textAlign: 'right',
          mb: 2
        }
      }
    }}
  />;
}
  const editColumn = useMemo<GridColDef[]>(
    () => [
      { 
        field: "expenseNo", 
        headerName: t("Expense No"), 
        editable: true, 
        flex: 0.5 
      },
      { 
        field: "projectCode", 
        headerName: t("Project Code"), 
        editable: false, 
        flex: 0.3,
      },
      { 
        field: "amount", 
        headerName: t("Amount (HKD)"), 
        editable: true, 
        flex: 0.5,
        type: 'number',
        renderEditCell: (params: GridRenderEditCellParams) => {
          return <CustomMoneyComponent params={params} />
        },
        valueFormatter: (params: GridValueFormatterParams) => {
          return CustomMoneyFormat(params.value as number)
        }
      },
      { field: "issuedDate", 
        headerName: t("Issue Date"), 
        editable: true, 
        flex: 0.4,  
        type: 'date', 
        valueGetter: (params) => {
          // console.log(params.row.issuedDate)
          return new Date(params.row.issuedDate)
        },
      },
      { 
        field: "remarks", 
        headerName: t("Remarks"), 
        editable: true,
        flex: 1,
      },
    ],
    [t]
  )


  return (
    <>
    <Stack
      spacing={2}
    >
      <Stack
        direction="row"
        justifyContent="right"
        flexWrap="wrap"
        spacing={2}
      >
        <Grid xs={12} justifyContent="right">
          <ButtonGroup variant="contained">
            <Button 
              startIcon={<AddIcon />} 
              variant="outlined" 
              component="label"
              onClick={() => toggleModals("createInvoiceModal")}
              >
              {t("Create expense")}
            </Button>
          </ButtonGroup>
        </Grid>
      </Stack>
      <SearchBox
        criteria={searchCriteria}
        onSearch={(query) => {
          setFilteredExpenses(
          expenses.filter(
            (e) =>
              e.projectCode.toLowerCase().includes(query.projectCode.toLowerCase()) &&
              e.projectName.toLowerCase().includes(query.projectName.toLowerCase()) &&
              (query.team === "All" || query.team.toLowerCase().includes(e.team.toLowerCase()))
          ),
          );
        }}
        onReset={onReset}
      />
      <Divider sx={{ paddingBlockStart: 2 }} />
      <Card sx={{ display: "block" }}>
        <CardContent>
          <Stack direction="row" justifyContent="space-between">
            <Typography variant="h6">
              {t("Total Amount (HKD)")}:
            </Typography>
            <Typography variant="h6">
              {moneyFormatter.format(filteredExpenses.reduce((acc, curr) => (acc + curr.amount), 0))}
            </Typography>
          </Stack>
          {/* s */}
        </CardContent>
      </Card>
      <Divider sx={{ paddingBlockEnd: 2 }} />
      <SearchResults<ProjectExpensesResultFormatted>
        items={filteredExpenses}
        columns={columns}
      />
    </Stack>

    <Dialog open={dialogOpen} onClose={handleCloseDialog} maxWidth="lg" fullWidth>
      <DialogTitle>{t("Edit Expense")}</DialogTitle>
      <DialogContent>
        <DialogContentText>
          {t("You can edit the expense details here.")}
        </DialogContentText>
        <StyledDataGrid
          apiRef={apiRef}
          autoHeight
          sx={{
          "--DataGrid-overlayHeight": "100px",
          ".MuiDataGrid-row .MuiDataGrid-cell.hasError": {
            border: "1px solid",
            borderColor: "error.main",
          },
          ".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": {
            border: "1px solid",
            borderColor: "warning.main",
          },
          '& .MuiDataGrid-columnHeaderTitle': {
            whiteSpace: 'normal',
            textWrap: 'pretty',
            textAlign: 'center',
          },
          '.MuiDataGrid-row:not(.MuiDataGrid-row--dynamicHeight)>.MuiDataGrid-cell': {
            overflow: 'auto',
            whiteSpace: 'nowrap',
            textWrap: 'pretty',
          },
          width: "100%", // Make the DataGrid wider
        }}
        disableColumnMenu
        editMode="row"
        rows={selectedRow}
        rowModesModel={rowModesModel}
        onRowModesModelChange={setRowModesModel}
        onRowEditStop={handleEditStop}
        columns={editColumn}
        getCellClassName={(params: GridCellParams<expenseRow>) => {
          let classname = "";
          if (params.row._error?.[params.field as keyof ExpenseRowError]) {
            classname = "hasError";
          } 
          return classname;
        }}
      />
      </DialogContent>
      <DialogActions>
      <Button onClick={handleDeleteExpense} color="error">
          {t("Delete")}
        </Button>
        <Button onClick={handleCloseDialog} color="primary">
          {t("Cancel")}
        </Button>
        <Button 
          onClick={handleSaveDialog} 
          color="primary"
          disabled={
            Object.values(rowModesModel).some((mode) => mode.mode === GridRowModes.Edit) || 
            selectedRow.some((row) => row._error)
          }
        >
          {t("Save")}
        </Button>
      </DialogActions>
    </Dialog>


      <CreateExpenseModal
        isOpen={modalsOpen.createInvoiceModal}
        onClose={() => toggleModals("createInvoiceModal")}
        projects={projects}
      />
      </>
  );
};
export default ExpenseSearch;
