import { useDeferredValue, useEffect, useMemo, useState } from 'react';
import { Button, DatePicker, Empty, Input, Modal, Spin, Table, Tree, message } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { UserOutlined } from '@ant-design/icons';
import zhCN from 'antd/es/date-picker/locale/zh_CN';
import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { useNavigate } from 'react-router-dom';
import PageBackButton from '@/components/PageBackButton';
import { getProjectExecutionInfo } from '@/api/projectExecution';
import { deptTreeSelect, getUserProfile, listUser } from '@/api/system/user';
import './user-project.css';

const { RangePicker } = DatePicker;

interface RoleRow {
  roleName?: string;
}

interface UserRow {
  _rowKey?: string;
  userId?: string | number;
  nickName?: string;
  userName?: string;
  phonenumber?: string;
  dept?: { deptName?: string };
  roles?: RoleRow[];
  [key: string]: unknown;
}

interface ProjectExecutionRow {
  projectId?: string | number;
  projectName?: string;
  allWorkTime?: string | number;
  detailList?: Array<string | number | null | undefined>;
  [key: string]: unknown;
}


interface DeptTreeNode {
  key: string;
  title: string;
  rawId: string | number;
  children?: DeptTreeNode[];
}

const isObject = (value: unknown): value is Record<string, unknown> =>
  typeof value === 'object' && value !== null;

const normalizeResponseData = (response: unknown) =>
  isObject(response) && response.data !== undefined ? response.data : response;

const toNumber = (value: unknown, fallback = 0) => {
  const num = Number(value);
  return Number.isFinite(num) ? num : fallback;
};

const getDefaultRange = (): [Dayjs, Dayjs] => [dayjs().startOf('month'), dayjs().endOf('month')];

const normalizeExecutionRows = (payload: unknown): ProjectExecutionRow[] => {
  const data = normalizeResponseData(payload);
  const rows = Array.isArray(data)
    ? data
    : isObject(data) && Array.isArray(data.rows)
      ? data.rows
      : [];
  return rows.filter(isObject) as ProjectExecutionRow[];
};

const normalizeUserRows = (payload: unknown): { rows: UserRow[]; total: number } => {
  const data = normalizeResponseData(payload);
  const rows = Array.isArray(data)
    ? data
    : isObject(data) && Array.isArray(data.rows)
      ? data.rows
      : [];
  const total = isObject(data) ? toNumber(data.total, rows.length) : rows.length;
  return {
    rows: rows.filter(isObject).map((row, index) => ({
      ...(row as UserRow),
      _rowKey: String((row as UserRow).userId ?? (row as UserRow).userName ?? `user_${index}`),
    })) as UserRow[],
    total,
  };
};

const normalizeDeptTreeNodes = (payload: unknown): DeptTreeNode[] => {
  const data = normalizeResponseData(payload);
  if (!Array.isArray(data)) {
    return [];
  }

  const mapNodes = (nodes: unknown[]): DeptTreeNode[] =>
    nodes.flatMap((node, index) => {
      if (!isObject(node)) {
        return [];
      }
      const rawId = node.id ?? node.deptId ?? node.value ?? `dept_${index}`;
      const normalizedId = typeof rawId === 'string' || typeof rawId === 'number' ? rawId : String(rawId);
      return [
        {
          key: String(normalizedId),
          rawId: normalizedId,
          title: String(node.label ?? node.title ?? node.deptName ?? normalizedId),
          children: Array.isArray(node.children) ? mapNodes(node.children) : undefined,
        },
      ];
    });

  return mapNodes(data);
};

const collectDeptKeys = (nodes: DeptTreeNode[]): string[] =>
  nodes.flatMap((node) => [node.key, ...(Array.isArray(node.children) ? collectDeptKeys(node.children) : [])]);

const getUserDisplayName = (user?: UserRow | null) => String(user?.nickName ?? user?.userName ?? '-');

const matchesUserKeyword = (user: UserRow, keyword: string) => {
  const normalizedKeyword = keyword.trim();
  if (!normalizedKeyword) {
    return true;
  }
  return [user.nickName, user.userName, user.phonenumber].some((field) =>
    String(field ?? '')
      .toLowerCase()
      .includes(normalizedKeyword.toLowerCase()),
  );
};

const UserProjectPage = () => {
  const navigate = useNavigate();
  const [loading, setLoading] = useState(false);
  const [userLoading, setUserLoading] = useState(false);
  const [deptLoading, setDeptLoading] = useState(false);
  const [userModalOpen, setUserModalOpen] = useState(false);
  const [userKeyword, setUserKeyword] = useState('');
  const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>(getDefaultRange());
  const [selectedUser, setSelectedUser] = useState<UserRow | null>(null);
  const [selectedUserId, setSelectedUserId] = useState<string | number>('');
  const [selectedUserName, setSelectedUserName] = useState('');
  const [pendingUserId, setPendingUserId] = useState<string | number>('');
  const [executionData, setExecutionData] = useState<ProjectExecutionRow[]>([]);
  const [userListData, setUserListData] = useState<UserRow[]>([]);
  const [deptTree, setDeptTree] = useState<DeptTreeNode[]>([]);
  const [expandedDeptKeys, setExpandedDeptKeys] = useState<string[]>([]);
  const [selectedDeptId, setSelectedDeptId] = useState<string>('');
  const [userPageNum, setUserPageNum] = useState(1);
  const [userPageSize, setUserPageSize] = useState(10);
  const [userTotal, setUserTotal] = useState(0);
  const deferredUserKeyword = useDeferredValue(userKeyword);

  useEffect(() => {
    const fetchCurrentUser = async () => {
      try {
        const response = await getUserProfile();
        const payload = normalizeResponseData(response);
        const user = isObject(payload) && isObject(payload.user) ? payload.user : payload;
        if (!isObject(user)) {
          return;
        }
        const nextUser: UserRow = {
          userId: user.userId as string | number | undefined,
          nickName: user.nickName as string | undefined,
          userName: user.userName as string | undefined,
        };
        setSelectedUser(nextUser);
        setSelectedUserId(nextUser.userId ?? '');
        setPendingUserId(nextUser.userId ?? '');
        setSelectedUserName(getUserDisplayName(nextUser));
      } catch (error) {
        console.error('Failed to fetch current user profile for user project page:', error);
        message.error('获取当前用户失败');
      }
    };
    void fetchCurrentUser();
  }, []);

  useEffect(() => {
    const fetchUserProject = async () => {
      if (!selectedUserId || !dateRange[0] || !dateRange[1]) {
        return;
      }
      setLoading(true);
      try {
        const response = await getProjectExecutionInfo({
          startDate: `${dateRange[0].format('YYYY-MM-DD')} 00:00:00`,
          endDate: `${dateRange[1].format('YYYY-MM-DD')} 00:00:00`,
          userId: selectedUserId,
        });
        setExecutionData(normalizeExecutionRows(response));
      } catch (error) {
        console.error('Failed to fetch user project table:', error);
        message.error('获取人员项目表失败');
        setExecutionData([]);
      } finally {
        setLoading(false);
      }
    };
    void fetchUserProject();
  }, [dateRange, selectedUserId]);

  useEffect(() => {
    if (!userModalOpen) {
      return;
    }
    const fetchDeptTree = async () => {
      setDeptLoading(true);
      try {
        const response = await deptTreeSelect();
        const treeNodes = normalizeDeptTreeNodes(response);
        setDeptTree(treeNodes);
        setExpandedDeptKeys(collectDeptKeys(treeNodes));
      } catch (error) {
        console.error('Failed to fetch department tree for user project page:', error);
        setDeptTree([]);
        setExpandedDeptKeys([]);
      } finally {
        setDeptLoading(false);
      }
    };
    void fetchDeptTree();
  }, [userModalOpen]);

  useEffect(() => {
    if (!userModalOpen) {
      return;
    }
    const fetchUserList = async () => {
      setUserLoading(true);
      try {
        const normalizedKeyword = deferredUserKeyword.trim();
        const response = await listUser({
          pageNum: userPageNum,
          pageSize: normalizedKeyword ? 1000 : userPageSize,
          deptId: selectedDeptId || undefined,
        });
        const { rows, total } = normalizeUserRows(response);
        const filteredRows = normalizedKeyword ? rows.filter((item) => matchesUserKeyword(item, normalizedKeyword)) : rows;
        setUserListData(filteredRows);
        setUserTotal(normalizedKeyword ? filteredRows.length : total);
      } catch (error) {
        console.error('Failed to fetch user list for user project page:', error);
        message.error('获取用户列表失败');
        setUserListData([]);
        setUserTotal(0);
      } finally {
        setUserLoading(false);
      }
    };
    void fetchUserList();
  }, [deferredUserKeyword, selectedDeptId, userModalOpen, userPageNum, userPageSize]);

  const pendingUser = useMemo(
    () => userListData.find((item) => String(item.userId ?? '') === String(pendingUserId ?? '')) ?? selectedUser,
    [pendingUserId, selectedUser, userListData],
  );


  const openUserModal = () => {
    setPendingUserId(selectedUserId);
    setUserPageNum(1);
    setSelectedDeptId('');
    setUserModalOpen(true);
  };

  const applySelectedUser = (user?: UserRow | null) => {
    setSelectedUser(user ?? null);
    setSelectedUserId(user?.userId ?? '');
    setSelectedUserName(getUserDisplayName(user));
    setPendingUserId(user?.userId ?? '');
    setUserModalOpen(false);
  };

  const dynamicColumns = useMemo<ColumnsType<ProjectExecutionRow>>(() => {
    const columns: ColumnsType<ProjectExecutionRow> = [
      {
        title: '项目',
        dataIndex: 'projectName',
        key: 'projectName',
        fixed: 'left',
        width: 180,
        render: (value: unknown, row) => (
          <Button
            type="link"
            className="user-project-link"
            onClick={() => navigate(`/project/detail?id=${String(row.projectId ?? '')}`)}
          >
            {String(value ?? '-')}
          </Button>
        ),
      },
      {
        title: '统计工时\n（天）',
        dataIndex: 'allWorkTime',
        key: 'allWorkTime',
        fixed: 'left',
        width: 140,
        render: (value: unknown) => toNumber(value, 0),
      },
    ];

    let cursor = dateRange[0].startOf('day');
    let index = 0;
    while (!cursor.isAfter(dateRange[1], 'day')) {
      const columnIndex = index;
      const key = cursor.format('M/D');
      const weekLabel = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][cursor.day()];
      columns.push({
        title: <span className="user-project-header">{`${weekLabel}\n${key}`}</span>,
        key: `detail-${key}`,
        dataIndex: 'detailList',
        width: 100,
        render: (value: unknown) => {
          const detailList = Array.isArray(value) ? value : [];
          return detailList[columnIndex] ?? '';
        },
      });
      cursor = cursor.add(1, 'day');
      index += 1;
    }

    return columns;
  }, [dateRange, navigate]);

  const summaryValues = useMemo(() => {
    const dayCount = dateRange[1].startOf('day').diff(dateRange[0].startOf('day'), 'day') + 1;
    const totalWorkTime = executionData.reduce((sum, row) => sum + toNumber(row.allWorkTime, 0), 0);
    const dayTotals = Array.from({ length: Math.max(dayCount, 0) }, (_item, index) =>
      Number(
        executionData
          .reduce((sum, row) => sum + toNumber(Array.isArray(row.detailList) ? row.detailList[index] : 0, 0), 0)
          .toFixed(2),
      ),
    );
    return { totalWorkTime: Number(totalWorkTime.toFixed(2)), dayTotals };
  }, [dateRange, executionData]);

  return (
    <div className="user-project-page">
      <div className="user-project-back-row">
        <PageBackButton text="返回看板统计" fallbackPath="/projectBank/projectProgress" />
      </div>

      <div className="user-project-shell">
        <div className="user-project-header-row">
          <h2 className="user-project-title">人员项目表</h2>
          <div className="user-project-toolbar">
            <div className="user-project-user-box">
              <span>选择人员</span>
              <Input
                value={selectedUserName}
                placeholder="请选择用户"
                readOnly
                suffix={<UserOutlined onClick={openUserModal} />}
                onClick={openUserModal}
              />
            </div>
            <div className="user-project-range-box">
              <span>统计时间：</span>
              <RangePicker
                value={dateRange}
                onChange={(values) => {
                  if (!values || values.length !== 2 || !values[0] || !values[1]) {
                    return;
                  }
                  setDateRange([values[0], values[1]]);
                }}
                allowClear={false}
                locale={zhCN}
                format="YYYY-MM-DD"
              />
            </div>
          </div>
        </div>

        <Spin spinning={loading}>
          <Table<ProjectExecutionRow>
            className="user-project-table"
            rowKey={(row) => String(row.projectId ?? row.projectName ?? '')}
            columns={dynamicColumns}
            dataSource={executionData}
            pagination={false}
            locale={{ emptyText: <Empty description="暂无项目数据" /> }}
            scroll={{ x: Math.max(dynamicColumns.length * 100, 960), y: 600 }}
            summary={() => (
              <Table.Summary.Row>
                <Table.Summary.Cell index={0}>合计工时（天）</Table.Summary.Cell>
                <Table.Summary.Cell index={1}>{summaryValues.totalWorkTime}</Table.Summary.Cell>
                {summaryValues.dayTotals.map((item, index) => (
                  <Table.Summary.Cell index={index + 2} key={`sum-${index}`}>
                    {item}
                  </Table.Summary.Cell>
                ))}
              </Table.Summary.Row>
            )}
          />
        </Spin>
      </div>

      <Modal
        title="选择人员"
        open={userModalOpen}
        onCancel={() => setUserModalOpen(false)}
        width={980}
        wrapClassName="user-select-dialog"
        destroyOnHidden
        footer={[
          <Button key="cancel" onClick={() => setUserModalOpen(false)}>
            取消
          </Button>,
          <Button
            key="ok"
            type="primary"
            disabled={!pendingUserId}
            onClick={() => {
              const hit =
                userListData.find((item) => String(item.userId ?? '') === String(pendingUserId ?? '')) ?? pendingUser;
              applySelectedUser(hit);
            }}
          >
            确认
          </Button>,
        ]}
      >
        <div className="user-select-modal user-select-modal-layout">
          <div className="user-select-dept-panel">
            <Spin spinning={deptLoading}>
              <Tree
                blockNode
                showLine
                className="user-select-dept-tree"
                expandedKeys={expandedDeptKeys}
                selectedKeys={selectedDeptId ? [selectedDeptId] : []}
                treeData={deptTree}
                onExpand={(keys) => setExpandedDeptKeys(keys as string[])}
                onSelect={(keys) => {
                  setSelectedDeptId(String(keys[0] ?? ''));
                  setUserPageNum(1);
                }}
              />
            </Spin>
          </div>
          <div className="user-select-table-panel">
            <div className="user-select-query-bar">
              <Input
                placeholder="请输入姓名或手机号"
                value={userKeyword}
                onChange={(event) => {
                  const nextValue = event.target.value;
                  setUserPageNum(1);
                  setUserKeyword(nextValue);
                }}
                allowClear
                size="large"
              />
            </div>
            <Table<UserRow>
              rowKey={(row) => String(row._rowKey ?? row.userId ?? row.userName ?? '')}
              loading={userLoading}
              dataSource={userListData}
              size="middle"
              scroll={{ y: 420 }}
              rowClassName={(record) =>
                String(record.userId ?? '') === String(pendingUserId ?? '') ? 'user-select-row is-active' : 'user-select-row'
              }
              onRow={(record) => ({
                onClick: () => {
                  setPendingUserId(record.userId ?? '');
                },
                onDoubleClick: () => {
                  applySelectedUser(record);
                },
              })}
              locale={{ emptyText: <Empty description="暂无人员数据" /> }}
              pagination={{
                current: userPageNum,
                pageSize: userPageSize,
                total: userTotal,
                showSizeChanger: true,
                showTotal: (total) => `共 ${total} 条`,
                onChange: (page, pageSize) => {
                  setUserPageNum(page);
                  setUserPageSize(pageSize);
                },
              }}
              columns={[
                {
                  title: '序号',
                  key: 'index',
                  width: 90,
                  render: (_value, _row, index) => (userPageNum - 1) * userPageSize + index + 1,
                },
                {
                  title: '姓名',
                  dataIndex: 'nickName',
                  key: 'nickName',
                  width: 180,
                  render: (_value, row) => (
                    <div className="user-select-name-cell">
                      <strong>{getUserDisplayName(row)}</strong>
                    </div>
                  ),
                },
                {
                  title: '部门',
                  dataIndex: ['dept', 'deptName'],
                  key: 'deptName',
                  width: 220,
                  render: (value: unknown) => String(value ?? '-'),
                },
                {
                  title: '角色',
                  dataIndex: 'roles',
                  key: 'roles',
                  render: (value: unknown) =>
                    Array.isArray(value) && value.length
                      ? value.map((item) => String((item as RoleRow)?.roleName ?? '')).filter(Boolean).join('、')
                      : '-',
                },
              ]}
            />
          </div>
        </div>
      </Modal>
    </div>
  );
};

export default UserProjectPage;
