"use client"

import {
  Button,
  Group,
  Modal,
  Paper,
  Stack,
  Text,
  TextInput,
  type ButtonProps,
  type GroupProps,
  type PaperProps,
  type StackProps,
} from "@mantine/core"
import { notifications } from "@mantine/notifications"
import {
  DataTable,
  type DataTableDefaultColumnProps,
  type DataTableProps,
} from "mantine-datatable"
import {
  type CSSProperties,
  type KeyboardEvent,
  type PropsWithChildren,
  type ReactNode,
  useCallback,
  useEffect,
  useMemo,
  useState,
} from "react"
import { create } from "zustand"
import {
  persist,
  type PersistStorage,
  type StorageValue,
} from "zustand/middleware"
import classes from "./PageSurface.module.css"

function mergeClassName(...classNames: Array<string | undefined>) {
  return classNames.filter(Boolean).join(" ")
}

export const settingModalClassNames = {
  content: classes.modalContent,
  header: classes.modalHeader,
  title: classes.modalTitle,
  body: classes.modalBody,
}

export const settingModalFormClassName = classes.modalForm
export const settingModalActionsClassName = classes.modalActions
export const settingModalMetaTextClassName = classes.modalMetaText
export const settingSurfaceClassNames = classes

const CUSTOM_PAGE_SIZE_STORAGE_KEY = "cowa:custom-records-per-page-options:v1"

function normalizePageSizeOptions(values: number[]) {
  return Array.from(
    new Set(values.filter((value) => Number.isInteger(value) && value > 0))
  ).sort((a, b) => a - b)
}

type AddCustomPageSizeResult = "added" | "exists" | "invalid"

type CustomPageSizePersistedState = {
  customPageSizeCache: number[]
}

type CustomPageSizeStoreState = CustomPageSizePersistedState & {
  appendCustomPageSize: (size: number) => void
  clearCustomPageSizeCache: () => void
}

function normalizeCustomPageSizePersistedState(
  value: unknown
): CustomPageSizePersistedState {
  if (!value || typeof value !== "object") {
    return { customPageSizeCache: [] }
  }

  const { customPageSizeCache } = value as {
    customPageSizeCache?: unknown
  }
  if (!Array.isArray(customPageSizeCache)) {
    return { customPageSizeCache: [] }
  }

  return {
    customPageSizeCache: normalizePageSizeOptions(
      customPageSizeCache.map((item) => Number(item))
    ),
  }
}

const customPageSizeStorage: PersistStorage<CustomPageSizePersistedState> = {
  getItem: (name) => {
    if (typeof window === "undefined") return null

    try {
      const rawValue = window.localStorage.getItem(name)
      if (!rawValue) return null

      const parsedValue = JSON.parse(rawValue) as
        | StorageValue<CustomPageSizePersistedState>
        | number[]
        | null

      if (Array.isArray(parsedValue)) {
        return {
          state: {
            customPageSizeCache: normalizePageSizeOptions(
              parsedValue.map((item) => Number(item))
            ),
          },
          version: 0,
        }
      }

      if (!parsedValue || typeof parsedValue !== "object") return null

      return {
        ...parsedValue,
        state: normalizeCustomPageSizePersistedState(parsedValue.state),
      }
    } catch {
      return null
    }
  },
  setItem: (name, value) => {
    if (typeof window === "undefined") return

    try {
      const normalizedValue: StorageValue<CustomPageSizePersistedState> = {
        ...value,
        state: normalizeCustomPageSizePersistedState(value.state),
      }

      if (normalizedValue.state.customPageSizeCache.length === 0) {
        window.localStorage.removeItem(name)
        return
      }

      window.localStorage.setItem(name, JSON.stringify(normalizedValue))
    } catch {
      // Ignore persistence failures and keep the UI usable.
    }
  },
  removeItem: (name) => {
    if (typeof window === "undefined") return

    try {
      window.localStorage.removeItem(name)
    } catch {
      // Ignore persistence failures and keep the UI usable.
    }
  },
}

const useCustomPageSizeStore = create<CustomPageSizeStoreState>()(
  persist(
    (set) => ({
      customPageSizeCache: [],
      appendCustomPageSize: (size) =>
        set((state) => ({
          customPageSizeCache: normalizePageSizeOptions([
            ...state.customPageSizeCache,
            size,
          ]),
        })),
      clearCustomPageSizeCache: () => set({ customPageSizeCache: [] }),
    }),
    {
      name: CUSTOM_PAGE_SIZE_STORAGE_KEY,
      storage: customPageSizeStorage,
      partialize: (state) => ({
        customPageSizeCache: state.customPageSizeCache,
      }),
    }
  )
)

export function usePersistentPageSizeOptions(
  defaultOptions: number[],
  currentPageSize?: number
) {
  const normalizedDefaultOptions = useMemo(
    () => normalizePageSizeOptions(defaultOptions),
    [defaultOptions]
  )
  const customPageSizeCache = useCustomPageSizeStore(
    (state) => state.customPageSizeCache
  )
  const appendCustomPageSize = useCustomPageSizeStore(
    (state) => state.appendCustomPageSize
  )
  const clearCustomPageSizeCache = useCustomPageSizeStore(
    (state) => state.clearCustomPageSizeCache
  )

  useEffect(() => {
    void useCustomPageSizeStore.persist.rehydrate()

    const handleStorage = (event: StorageEvent) => {
      if (event.key !== CUSTOM_PAGE_SIZE_STORAGE_KEY) return
      void useCustomPageSizeStore.persist.rehydrate()
    }

    window.addEventListener("storage", handleStorage)
    return () => {
      window.removeEventListener("storage", handleStorage)
    }
  }, [])

  const persistedRecordsPerPageOptions = useMemo(
    () =>
      normalizePageSizeOptions([
        ...normalizedDefaultOptions,
        ...customPageSizeCache,
      ]),
    [customPageSizeCache, normalizedDefaultOptions]
  )

  const recordsPerPageOptions = useMemo(() => {
    const nextOptions = [...persistedRecordsPerPageOptions]
    if (
      typeof currentPageSize === "number" &&
      Number.isInteger(currentPageSize) &&
      currentPageSize > 0
    ) {
      nextOptions.push(currentPageSize)
    }
    return normalizePageSizeOptions(nextOptions)
  }, [currentPageSize, persistedRecordsPerPageOptions])

  const addCustomPageSize = useCallback(
    (size: number): AddCustomPageSizeResult => {
      if (!Number.isInteger(size) || size <= 0) return "invalid"
      if (persistedRecordsPerPageOptions.includes(size)) return "exists"

      appendCustomPageSize(size)
      return "added"
    },
    [appendCustomPageSize, persistedRecordsPerPageOptions]
  )

  return {
    recordsPerPageOptions,
    hasCustomPageSizeCache: customPageSizeCache.length > 0,
    addCustomPageSize,
    clearCustomPageSizeCache,
  }
}

type SettingCustomPageSizeControlProps = {
  addCustomPageSize: (size: number) => AddCustomPageSizeResult
  clearCustomPageSizeCache: () => void
  hasCustomPageSizeCache: boolean
  triggerButtonProps?: Omit<ButtonProps, "children" | "onClick">
  confirmButtonProps?: Omit<ButtonProps, "children" | "onClick">
  triggerLabel?: ReactNode
}

export function SettingCustomPageSizeControl({
  addCustomPageSize,
  clearCustomPageSizeCache,
  hasCustomPageSizeCache,
  triggerButtonProps,
  confirmButtonProps,
  triggerLabel = "自定义每页条数",
}: SettingCustomPageSizeControlProps) {
  const [opened, setOpened] = useState(false)
  const [customPageSizeInput, setCustomPageSizeInput] = useState("")

  const closeCustomPageSizeModal = useCallback(() => {
    setOpened(false)
    setCustomPageSizeInput("")
  }, [])

  const handleAddCustomPageSize = useCallback(() => {
    const rawValue = customPageSizeInput.trim()
    if (!rawValue) return

    const size = Number(rawValue)
    const result = addCustomPageSize(size)

    if (result === "invalid") {
      notifications.show({
        color: "red",
        title: "输入无效",
        message: "请填写大于 0 的整数条数",
      })
      return
    }

    if (result === "exists") {
      notifications.show({
        color: "blue",
        title: "已存在",
        message: `每页 ${size} 条已在可选项中`,
      })
      return
    }

    closeCustomPageSizeModal()
    notifications.show({
      color: "green",
      title: "添加成功",
      message: `已新增每页 ${size} 条`,
    })
  }, [addCustomPageSize, closeCustomPageSizeModal, customPageSizeInput])

  const handleCustomPageSizeEnter = useCallback(
    (event: KeyboardEvent<HTMLInputElement>) => {
      if (event.key !== "Enter") return
      event.preventDefault()
      handleAddCustomPageSize()
    },
    [handleAddCustomPageSize]
  )

  const handleClearCachedPageSizes = useCallback(() => {
    clearCustomPageSizeCache()
    closeCustomPageSizeModal()
    notifications.show({
      color: "green",
      title: "清除成功",
      message: "已清除自定义每页条数缓存",
    })
  }, [clearCustomPageSizeCache, closeCustomPageSizeModal])

  return (
    <>
      <Button
        variant="light"
        color="gray"
        size="xs"
        onClick={() => setOpened(true)}
        {...triggerButtonProps}>
        {triggerLabel}
      </Button>
      <Modal
        opened={opened}
        onClose={closeCustomPageSizeModal}
        title="添加每页条数"
        classNames={settingModalClassNames}
        centered>
        <Stack gap={12} className={settingModalFormClassName}>
          <TextInput
            data-autofocus
            label="每页条数"
            placeholder="请输入大于 0 的整数，例如 99"
            value={customPageSizeInput}
            onChange={(event) =>
              setCustomPageSizeInput(event.currentTarget.value)
            }
            onKeyDown={handleCustomPageSizeEnter}
          />
          <Text className={settingModalMetaTextClassName}>
            已添加的自定义条数会缓存在当前浏览器中，可随时清除。
          </Text>
          <Group
            justify={hasCustomPageSizeCache ? "space-between" : "flex-end"}
            className={settingModalActionsClassName}
            wrap="wrap">
            {hasCustomPageSizeCache ? (
              <Button
                variant="subtle"
                color="red"
                onClick={handleClearCachedPageSizes}>
                清除缓存
              </Button>
            ) : null}
            <Group gap={12}>
              <Button variant="default" onClick={closeCustomPageSizeModal}>
                取消
              </Button>
              <Button onClick={handleAddCustomPageSize} {...confirmButtonProps}>
                添加
              </Button>
            </Group>
          </Group>
        </Stack>
      </Modal>
    </>
  )
}

export function SettingPage({
  className,
  ...props
}: PropsWithChildren<StackProps>) {
  return (
    <Stack
      w="100%"
      h="calc(100vh - 60px)"
      p="md"
      gap="md"
      className={mergeClassName(classes.page, className)}
      {...props}
    />
  )
}

export function SettingPanel({
  className,
  withBorder = true,
  radius = "sm",
  p = "md",
  shadow,
  ...props
}: PropsWithChildren<PaperProps>) {
  return (
    <Paper
      withBorder={withBorder}
      radius={radius}
      p={p}
      shadow={shadow}
      className={mergeClassName(classes.panel, className)}
      {...props}
    />
  )
}

export function SettingFilterPanel({
  className,
  ...props
}: PropsWithChildren<PaperProps>) {
  return (
    <SettingPanel
      className={mergeClassName(classes.filterPanel, className)}
      {...props}
    />
  )
}

export function SettingContentPanel({
  className,
  ...props
}: PropsWithChildren<PaperProps>) {
  return (
    <SettingPanel
      className={mergeClassName(classes.contentPanel, className)}
      {...props}
    />
  )
}

type SettingListHeaderProps = {
  title: ReactNode
  count?: ReactNode
  actions?: ReactNode
  className?: string
}

export function SettingListHeader({
  title,
  count,
  actions,
  className,
}: SettingListHeaderProps) {
  const isPlainCount = typeof count === "string" || typeof count === "number"

  return (
    <Group
      justify="space-between"
      align="center"
      wrap="wrap"
      gap="sm"
      className={mergeClassName(classes.listHeader, className)}>
      <Group gap="xs">
        <Text className={classes.listHeaderTitle}>{title}</Text>
        {count !== undefined ? (
          isPlainCount ? (
            <Text className={classes.listHeaderCount}>{count}</Text>
          ) : (
            <div className={classes.listHeaderCount}>{count}</div>
          )
        ) : null}
      </Group>
      {actions}
    </Group>
  )
}

export function SettingHeaderActions({
  className,
  gap = "sm",
  ...props
}: PropsWithChildren<GroupProps>) {
  return (
    <Group
      gap={gap}
      wrap="wrap"
      className={mergeClassName(classes.headerActions, className)}
      {...props}
    />
  )
}

export function SettingFilterActions({
  className,
  gap = "sm",
  justify = "flex-end",
  mt = "md",
  ...props
}: PropsWithChildren<GroupProps>) {
  return (
    <Group
      justify={justify}
      gap={gap}
      wrap="wrap"
      mt={mt}
      className={mergeClassName(classes.filterActions, className)}
      {...props}
    />
  )
}

type SettingInlineFilterFieldProps = {
  label: ReactNode
  children: ReactNode
  className?: string
  labelClassName?: string
  controlClassName?: string
  labelWidth?: number | string
}

export function SettingInlineFilterField({
  label,
  children,
  className,
  labelClassName,
  controlClassName,
  labelWidth = 80,
}: SettingInlineFilterFieldProps) {
  const style = {
    "--setting-inline-filter-label-width":
      typeof labelWidth === "number" ? `${labelWidth}px` : labelWidth,
  } as CSSProperties

  return (
    <div
      style={style}
      className={mergeClassName(classes.filterField, className)}>
      <Text className={mergeClassName(classes.filterLabel, labelClassName)}>
        {label}
      </Text>
      <div className={mergeClassName(classes.filterControl, controlClassName)}>
        {children}
      </div>
    </div>
  )
}

const settingDataTableStyles = {
  header: {
    backgroundColor: "#F7F8FA",
    borderBottom: "1px solid #E5E6EB",
    color: "#4E5969",
    fontSize: "14px",
    fontWeight: 500,
  },
  root: {
    maxWidth: "100%",
    minWidth: 0,
    fontSize: "14px",
    color: "#1D2129",
    borderBottom: "1px solid #E5E6EB",
    borderRadius: 4,
    overflow: "hidden",
    boxSizing: "border-box",
    backgroundColor: "#FFFFFF",
  },
  table: {
    backgroundColor: "#FFFFFF",
  },
  footer: {
    backgroundColor: "#FFFFFF",
  },
  pagination: {
    padding: "12px 16px",
    borderTop: "1px solid #E5E6EB",
  },
} as const

const settingDataTableDefaultColumnProps: DataTableDefaultColumnProps<
  Record<string, unknown>
> = {
  titleStyle: {
    whiteSpace: "nowrap",
    fontWeight: 500,
  },
}

export function SettingDataTable<T = Record<string, unknown>>(
  props: DataTableProps<T>
) {
  const {
    styles,
    defaultColumnProps,
    withTableBorder,
    withRowBorders,
    striped,
    highlightOnHover,
    loaderBackgroundBlur,
    loadingText,
    noRecordsText,
    minHeight,
    maxHeight,
    height,
    page,
    onPageChange,
    totalRecords,
    recordsPerPage,
    recordsPerPageLabel,
    paginationText,
    scrollAreaProps,
    ...rest
  } = props

  const paginationProps =
    page !== undefined &&
    onPageChange !== undefined &&
    recordsPerPage !== undefined
      ? {
          page,
          onPageChange,
          totalRecords,
          recordsPerPage,
          loadingText: loadingText ?? "正在加载数据...",
          recordsPerPageLabel: recordsPerPageLabel ?? "每页条数",
          paginationText:
            paginationText ??
            (({
              from,
              to,
              totalRecords,
            }: {
              from: number
              to: number
              totalRecords: number
            }) => `显示 ${from}-${to} 条，共 ${totalRecords} 条记录`),
        }
      : {}

  const tableProps = {
    withTableBorder: withTableBorder ?? true,
    withRowBorders: withRowBorders ?? true,
    striped: striped ?? false,
    highlightOnHover: highlightOnHover ?? false,
    defaultColumnProps:
      defaultColumnProps ??
      (settingDataTableDefaultColumnProps as DataTableDefaultColumnProps<T>),
    loaderBackgroundBlur: loaderBackgroundBlur ?? 0,
    noRecordsText: noRecordsText ?? "暂无数据",
    minHeight: minHeight ?? 360,
    maxHeight,
    height: height ?? (maxHeight !== undefined ? "auto" : undefined),
    scrollAreaProps: {
      type: "auto",
      ...scrollAreaProps,
    },
    styles: styles
      ? { ...settingDataTableStyles, ...styles }
      : settingDataTableStyles,
    ...paginationProps,
    ...rest,
  } as DataTableProps<T>

  return <DataTable {...tableProps} />
}

export const settingTabsStyles = {
  list: {
    padding: 4,
    backgroundColor: "#F7F8FA",
    border: "1px solid #E5E6EB",
    borderRadius: 4,
    gap: 8,
  },
  tab: {
    minHeight: 32,
    borderRadius: 4,
    padding: "0 12px",
    fontSize: 14,
    fontWeight: 500,
    lineHeight: "20px",
  },
  tabLabel: {
    color: "inherit",
    fontSize: 14,
    lineHeight: "20px",
  },
  panel: {
    flex: 1,
    minHeight: 0,
    minWidth: 0,
    paddingTop: 16,
  },
} as const

export const settingTabsClassNames = {
  list: classes.settingTabsList,
  tab: classes.settingTabsTab,
  tabLabel: classes.settingTabsTabLabel,
  panel: classes.settingTabsPanel,
} as const
