"use client";

import { memo, useCallback, useMemo, useRef, useState } from "react";
import {
  Box,
  Checkbox,
  IconButton,
  Paper,
  TablePagination,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Typography,
} from "@mui/material";
import EditNote from "@mui/icons-material/EditNote";
import DeleteIcon from "@mui/icons-material/Delete";
import { useRouter } from "next/navigation";
import { useTranslation } from "react-i18next";
import SearchBox, { Criterion } from "../SearchBox";
import { UserResult } from "@/app/api/user";
import { deleteUser } from "@/app/api/user/actions";
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
import { updateUser } from "@/app/api/user/client";

interface UserAuthItem {
  id: number;
  authority?: string;
  name?: string;
  description?: string | null;
  v?: number;
}

interface UserListDetail extends UserResult {
  authIds?: number[];
  auths?: UserAuthItem[];
}

interface Props {
  users: UserListDetail[];
}

function hasUserAuthority(user: UserListDetail, authorityId: number): boolean {
  return (user.auths ?? []).some(
    auth => auth.id === authorityId && (typeof auth.v === "number" ? auth.v === 1 : true),
  );
}

type SearchQuery = Partial<Omit<UserResult, "id">>;
type SearchParamNames = keyof SearchQuery;
type SearchBoxQuery = Record<string, string>;

const headerCellSx = {
  border: "1px solid #9e9e9e",
  fontWeight: 700,
  backgroundColor: "#f3f4f6",
  whiteSpace: "normal",
  wordBreak: "normal",
  overflowWrap: "normal",
  lineHeight: 1.2,
};

const bodyCellSx = {
  border: "1px solid #c6c6c6",
  whiteSpace: "nowrap",
};

/** Memoized so toggling one checkbox does not re-render every cell on the page. */
const AuthorityCheckboxCell = memo(function AuthorityCheckboxCell({
  checked,
  disabled,
  userId,
  authorityId,
  onToggle,
}: {
  checked: boolean;
  disabled: boolean;
  userId: number;
  authorityId: number;
  onToggle: (userId: number, authorityId: number, checked: boolean) => void;
}) {
  return (
    <TableCell sx={bodyCellSx} align="center">
      <Checkbox
        size="small"
        checked={checked}
        disabled={disabled}
        onChange={(_, next) => onToggle(userId, authorityId, next)}
      />
    </TableCell>
  );
});

const UserExcelSheetView: React.FC<Props> = ({ users }) => {
  const { t } = useTranslation("user");
  const router = useRouter();
  const [allUsers, setAllUsers] = useState(users);
  const allUsersRef = useRef(allUsers);
  allUsersRef.current = allUsers;
  const [searchQuery, setSearchQuery] = useState<SearchBoxQuery>({});
  const [updatingKey, setUpdatingKey] = useState<string | null>(null);
  const [page, setPage] = useState(0);
  const [rowsPerPage, setRowsPerPage] = useState(20);
  /** Prevents double-submit on the same checkbox; other cells stay clickable. */
  const inFlightKeysRef = useRef(new Set<string>());

  const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
    () => [
      { label: "用戶/姓名", paramName: "username", type: "text" },
      { label: t("staffNo"), paramName: "staffNo", type: "text" },
    ],
    [t],
  );

  const authorityColumns = useMemo(() => {
    const authorityMap = new Map<number, string>();
    users.forEach(user => {
      (user.auths ?? []).forEach(auth => {
        const label = auth.name?.trim() || auth.description?.trim() || auth.authority?.trim();
        if (!label) return;
        if (!authorityMap.has(auth.id)) authorityMap.set(auth.id, label);
      });
    });
    return Array.from(authorityMap.entries())
      .map(([id, label]) => ({ id, label }))
      .sort((a, b) => a.id - b.id);
  }, [users]);

  const filteredUsers = useMemo(() => {
    let results = allUsers;
    if (searchQuery.username?.trim()) {
      const keyword = searchQuery.username.trim().toLowerCase();
      results = results.filter(
        user =>
          user.username?.toLowerCase().includes(keyword) ||
          user.name?.toLowerCase().includes(keyword),
      );
    }
    if (searchQuery.staffNo?.trim()) {
      const keyword = searchQuery.staffNo.trim();
      results = results.filter(user => user.staffNo?.toString().includes(keyword));
    }
    return results;
  }, [allUsers, searchQuery]);

  const pagedUsers = useMemo(() => {
    const start = page * rowsPerPage;
    return filteredUsers.slice(start, start + rowsPerPage);
  }, [filteredUsers, page, rowsPerPage]);

  const handleEdit = useCallback(
    (user: UserResult) => {
      router.push(`/settings/user/edit?id=${user.id}`);
    },
    [router],
  );

  const handleDelete = useCallback(
    (user: UserResult) => {
      deleteDialog(async () => {
        await deleteUser(user.id);
        setAllUsers(prev => prev.filter(item => item.id !== user.id));
        router.refresh();
        successDialog(t("Delete Success"), t);
      }, t);
    },
    [router, t],
  );

  const handleAuthorityToggle = useCallback(
    async (userId: number, authorityId: number, checked: boolean) => {
      const user = allUsersRef.current.find(u => u.id === userId);
      if (!user || hasUserAuthority(user, authorityId) === checked) return;

      const key = `${userId}-${authorityId}`;
      if (inFlightKeysRef.current.has(key)) return;
      inFlightKeysRef.current.add(key);

      const updateList = (list: UserListDetail[], nextChecked: boolean) =>
        list.map(item =>
          item.id !== userId
            ? item
            : {
                ...item,
                auths: (item.auths ?? []).map(auth =>
                  auth.id === authorityId ? { ...auth, v: nextChecked ? 1 : 0 } : auth,
                ),
                authIds: nextChecked
                  ? Array.from(new Set([...(item.authIds ?? []), authorityId]))
                  : (item.authIds ?? []).filter(id => id !== authorityId),
              },
        );

      setAllUsers(prev => updateList(prev, checked));
      setUpdatingKey(key);
      try {
        await updateUser(userId, {
          username: user.username,
          name: user.name,
          staffNo: user.staffNo?.toString(),
          locked: false,
          addAuthIds: checked ? [authorityId] : [],
          removeAuthIds: checked ? [] : [authorityId],
        });
      } catch (error) {
        console.error("Failed to update authority", error);
        setAllUsers(prev => updateList(prev, !checked));
      } finally {
        setUpdatingKey(null);
        inFlightKeysRef.current.delete(key);
      }
    },
    [],
  );

  return (
    <>
      <SearchBox
        criteria={searchCriteria}
        onSearch={async query => {
          setSearchQuery(query as SearchBoxQuery);
          setPage(0);
        }}
      />

      <Paper variant="outlined" sx={{ mt: 2, overflow: "hidden" }}>
        <TableContainer sx={{ maxHeight: "calc(100vh - 280px)" }}>
          <Table stickyHeader size="small">
            <TableHead>
              <TableRow>
                <TableCell sx={{ ...headerCellSx, minWidth: 260 }}>
                  編輯 & 員工資訊
                </TableCell>
                {authorityColumns.map(authority => (
                  <TableCell
                    key={authority.id}
                    sx={{ ...headerCellSx, minWidth: 90, maxWidth: 110 }}
                    align="center"
                  >
                    {authority.label.replace(/\s+/g, "\n")}
                  </TableCell>
                ))}
                <TableCell sx={{ ...headerCellSx, minWidth: 78 }} align="center">
                  {t("Delete")}
                </TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {pagedUsers.length > 0 ? (
                pagedUsers.map((user, index) => (
                  <TableRow key={user.id} hover>
                    <TableCell sx={{ ...bodyCellSx, minWidth: 260, whiteSpace: "normal" }}>
                      <Box display="flex" flexDirection="column" gap={0.5}>
                        <Box display="flex" alignItems="center" gap={1}>
                          <IconButton size="small" color="primary" onClick={() => handleEdit(user)}>
                            <EditNote fontSize="small" />
                          </IconButton>
                          <Typography variant="body2" component="span">
                            #{page * rowsPerPage + index + 1}
                          </Typography>
                          <Typography variant="body2" component="span">
                            {user.staffNo}
                          </Typography>
                        </Box>
                        <Box display="flex" alignItems="center" gap={1}>
                          <Typography variant="body2" component="span" fontWeight={600}>
                            {user.username}
                          </Typography>
                          <Typography variant="body2" component="span" color="text.secondary">
                            {user.name}
                          </Typography>
                        </Box>
                      </Box>
                    </TableCell>
                    {authorityColumns.map(authority => (
                      <AuthorityCheckboxCell
                        key={authority.id}
                        userId={user.id}
                        authorityId={authority.id}
                        checked={hasUserAuthority(user, authority.id)}
                        disabled={updatingKey === `${user.id}-${authority.id}`}
                        onToggle={handleAuthorityToggle}
                      />
                    ))}
                    <TableCell sx={bodyCellSx} align="center">
                      <IconButton size="small" color="error" onClick={() => handleDelete(user)}>
                        <DeleteIcon fontSize="small" />
                      </IconButton>
                    </TableCell>
                  </TableRow>
                ))
              ) : (
                <TableRow>
                  <TableCell colSpan={2 + authorityColumns.length} sx={bodyCellSx}>
                    <Box py={2}>
                      <Typography variant="body2" color="text.secondary">
                        No data
                      </Typography>
                    </Box>
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        </TableContainer>
        <TablePagination
          component="div"
          count={filteredUsers.length}
          page={page}
          onPageChange={(_e, nextPage) => setPage(nextPage)}
          rowsPerPage={rowsPerPage}
          onRowsPerPageChange={e => {
            setRowsPerPage(parseInt(e.target.value, 10));
            setPage(0);
          }}
          rowsPerPageOptions={[10, 20, 50]}
          labelRowsPerPage="每頁"
        />
      </Paper>
    </>
  );
};

export default UserExcelSheetView;

