"use client"

import { TimeFilter } from "@/components/label/api/workload/typing"
import {
  Button,
  Group,
  Paper,
  Select,
  SimpleGrid,
  Stack,
  Text,
  TextInput,
} from "@mantine/core"
import { notifications } from "@mantine/notifications"
import { IconDownload, IconRefresh } from "@tabler/icons-react"
import dayjs from "dayjs"
import {
  DataTable,
  DataTableColumn,
  DataTableSortStatus,
} from "mantine-datatable"
import { useEffect, useMemo, useState } from "react"
import * as XLSX from "xlsx-js-style"
import {
  DimensionType,
  GroupedData,
  MetricColumn,
  dimensionOpts,
} from "./config"

function emptyGroupedData(): GroupedData {
  return {
    all: [],
    order_by_group_name: [],
    order_by_project_name: [],
    order_by_project_type: [],
    order_by_user_name: [],
  }
}

export default function WorkloadMetricsTable(props: {
  title: string
  sheetName: string
  fileName: string
  metrics: MetricColumn[]
  fetchData: (params: TimeFilter) => Promise<GroupedData>
}) {
  const { title, sheetName, fileName, metrics, fetchData } = props

  const [startDate, setStartDate] = useState(
    dayjs().subtract(1, "day").format("YYYY-MM-DD")
  )
  const [endDate, setEndDate] = useState(
    dayjs().subtract(1, "day").format("YYYY-MM-DD")
  )
  const [dimension, setDimension] = useState<DimensionType>("all")
  const [data, setData] = useState<GroupedData>(emptyGroupedData())
  const [loading, setLoading] = useState(false)

  const [projectName, setProjectName] = useState("")
  const [projectType, setProjectType] = useState("")
  const [userName, setUserName] = useState("")
  const [groupName, setGroupName] = useState("")

  const [sortStatus, setSortStatus] = useState<DataTableSortStatus>({
    columnAccessor: "work_time",
    direction: "desc",
  })

  const refresh = async () => {
    if (!startDate || !endDate) {
      notifications.show({
        color: "yellow",
        title: "参数不完整",
        message: "请选择起止日期",
      })
      return
    }
    try {
      setLoading(true)
      const res = await fetchData({
        start_date: startDate,
        end_date: endDate,
      })
      setData({
        ...emptyGroupedData(),
        ...(res ?? {}),
      })
    } catch (e) {
      notifications.show({
        color: "red",
        title: "加载失败",
        message: e instanceof Error ? e.message : "请求失败",
      })
      setData(emptyGroupedData())
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    queueMicrotask(refresh)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const filteredRecords = useMemo(() => {
    let records = [...(data[dimension] ?? [])]
    if (projectName.trim()) {
      records = records.filter((item) =>
        String(item.project_name ?? "")
          .toLowerCase()
          .includes(projectName.trim().toLowerCase())
      )
    }
    if (projectType.trim()) {
      records = records.filter((item) =>
        String(item.project_type ?? "")
          .toLowerCase()
          .includes(projectType.trim().toLowerCase())
      )
    }
    if (userName.trim()) {
      records = records.filter((item) =>
        String(item.user_name ?? "")
          .toLowerCase()
          .includes(userName.trim().toLowerCase())
      )
    }
    if (groupName.trim()) {
      records = records.filter((item) =>
        String(item.group_name ?? "")
          .toLowerCase()
          .includes(groupName.trim().toLowerCase())
      )
    }
    return records
  }, [data, dimension, groupName, projectName, projectType, userName])

  const sortedRecords = useMemo(() => {
    const list = [...filteredRecords]
    const accessor = sortStatus.columnAccessor
    const dir = sortStatus.direction === "asc" ? 1 : -1
    list.sort((a, b) => {
      const av = a?.[accessor as string]
      const bv = b?.[accessor as string]
      const an = Number(av)
      const bn = Number(bv)
      if (Number.isFinite(an) && Number.isFinite(bn)) {
        return (an - bn) * dir
      }
      return String(av ?? "").localeCompare(String(bv ?? "")) * dir
    })
    return list
  }, [filteredRecords, sortStatus.columnAccessor, sortStatus.direction])

  const baseColumns = useMemo(() => {
    const allCols: Record<DimensionType, DataTableColumn<any>[]> = {
      all: [
        { accessor: "project_name", title: "项目名称", width: 180 },
        { accessor: "project_type", title: "项目类型", width: 180 },
        { accessor: "user_name", title: "用户名", width: 120 },
        { accessor: "group_name", title: "用户组", width: 160 },
      ],
      order_by_group_name: [
        { accessor: "group_name", title: "用户组", width: 180 },
      ],
      order_by_project_name: [
        { accessor: "project_name", title: "项目名称", width: 220 },
      ],
      order_by_project_type: [
        { accessor: "project_type", title: "项目类型", width: 220 },
      ],
      order_by_user_name: [
        { accessor: "user_name", title: "用户名", width: 180 },
      ],
    }
    return allCols[dimension]
  }, [dimension])

  const columns = useMemo(() => {
    const metricCols = metrics.map((metric) => {
      return {
        accessor: metric.key,
        title: metric.title,
        width: 140,
        sortable: true,
      } as DataTableColumn<any>
    })
    return [
      {
        accessor: "index",
        title: "序号",
        width: 80,
        render: (_record: any, index: number) => index + 1,
      } as DataTableColumn<any>,
      ...baseColumns,
      ...metricCols,
    ]
  }, [baseColumns, metrics])

  const totals = useMemo(() => {
    return metrics.map((metric) => {
      const sum = sortedRecords.reduce((acc, item) => {
        const value = Number(item?.[metric.key] ?? 0)
        return acc + (Number.isFinite(value) ? value : 0)
      }, 0)
      return { title: metric.title, value: sum }
    })
  }, [metrics, sortedRecords])

  const handleExport = () => {
    if (!sortedRecords.length) {
      notifications.show({
        color: "yellow",
        title: "暂无数据",
        message: "当前筛选条件下无可导出数据",
      })
      return
    }
    const baseHeaders = baseColumns.map((c) => String(c.title ?? c.accessor))
    const metricHeaders = metrics.map((m) => m.title)
    const header = ["序号", ...baseHeaders, ...metricHeaders]

    const baseAccessors = baseColumns.map((c) => String(c.accessor))
    const rows = sortedRecords.map((item, index) => {
      return [
        index + 1,
        ...baseAccessors.map((key) => item?.[key] ?? "-"),
        ...metrics.map((m) => item?.[m.key] ?? 0),
      ]
    })

    const wb = XLSX.utils.book_new()
    const ws = XLSX.utils.aoa_to_sheet([header, ...rows])
    XLSX.utils.book_append_sheet(wb, ws, sheetName)
    XLSX.writeFile(wb, fileName)
  }

  const rowKey = useMemo(() => {
    if (dimension === "all") {
      return (record: any) =>
        `${record.project_id ?? "p"}_${record.uid ?? "u"}_${record.project_name ?? ""}_${record.user_name ?? ""}`
    }
    if (dimension === "order_by_group_name") return "group_name"
    if (dimension === "order_by_project_name") return "project_name"
    if (dimension === "order_by_project_type") return "project_type"
    return "user_name"
  }, [dimension])

  return (
    <Stack h="100%" gap="sm">
      <Paper withBorder p="sm" radius="sm">
        <Group justify="space-between" wrap="wrap">
          <Group>
            <Text size="sm" fw={700}>
              {title}
            </Text>
            <TextInput
              label="开始日期"
              size="xs"
              radius="xs"
              type="date"
              value={startDate}
              onChange={(e) => setStartDate(e.currentTarget.value)}
            />
            <TextInput
              label="结束日期"
              size="xs"
              radius="xs"
              type="date"
              value={endDate}
              onChange={(e) => setEndDate(e.currentTarget.value)}
            />
            <Button
              size="xs"
              radius="xs"
              leftSection={<IconRefresh size={16} />}
              onClick={refresh}
              loading={loading}>
              更新
            </Button>
          </Group>
          <Group>
            <Select
              label="聚合维度"
              size="xs"
              radius="xs"
              data={dimensionOpts}
              value={dimension}
              onChange={(v) => setDimension((v as DimensionType) || "all")}
            />
            <Button
              variant="default"
              size="xs"
              radius="xs"
              leftSection={<IconDownload size={16} />}
              onClick={handleExport}>
              下载数据
            </Button>
          </Group>
        </Group>

        <SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="sm" mt="sm">
          <TextInput
            label="项目名称"
            size="xs"
            radius="xs"
            value={projectName}
            onChange={(e) => setProjectName(e.currentTarget.value)}
          />
          <TextInput
            label="项目类型"
            size="xs"
            radius="xs"
            value={projectType}
            onChange={(e) => setProjectType(e.currentTarget.value)}
          />
          <TextInput
            label="用户名"
            size="xs"
            radius="xs"
            value={userName}
            onChange={(e) => setUserName(e.currentTarget.value)}
          />
          <TextInput
            label="用户组"
            size="xs"
            radius="xs"
            value={groupName}
            onChange={(e) => setGroupName(e.currentTarget.value)}
          />
        </SimpleGrid>
      </Paper>

      <Paper
        withBorder
        p="sm"
        radius="sm"
        style={{ flex: 1, minHeight: 0, display: "flex" }}>
        <DataTable<any>
          withTableBorder
          withRowBorders
          fetching={loading}
          records={sortedRecords}
          columns={columns}
          noRecordsText="暂无数据"
          idAccessor={rowKey as any}
          scrollAreaProps={{ type: "auto" }}
          style={{ width: "100%" }}
          sortStatus={sortStatus}
          onSortStatusChange={setSortStatus}
        />
      </Paper>

      <Paper withBorder p="sm" radius="sm">
        <Group wrap="wrap" gap="md">
          <Text size="sm" fw={700}>
            总计
          </Text>
          {totals.map((item) => (
            <Text size="sm" key={item.title}>
              {item.title}：{item.value}
            </Text>
          ))}
        </Group>
      </Paper>
    </Stack>
  )
}
