import { useMemo, useState, type ReactNode } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import dayjs, { type Dayjs } from 'dayjs'
import {
  Button, Card, DatePicker, Form, Input, InputNumber, Popconfirm, Select, Space, Tabs, message } from 'antd'
import CareTable from '../../components/CareTable'
import {
  DeleteOutlined, FileExcelOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons'
import Modal from '../../components/DraggableModal'
import client, { apiPrefix, unwrap, type ApiResponse } from '../../api/client'

export const money = (v: unknown) => (v == null || v === '' ? '-' : Number(v).toLocaleString())
export const options = (values: string[]) => values.map((value) => ({ value, label: value }))
export type Row = Record<string, unknown> & { id: number }
export type PageResult = { total: number; list: Row[]; counts?: Record<string, number> }

export type FieldDef = {
  key: string
  label: string
  kind?: 'text' | 'select' | 'date' | 'number' | 'textarea'
  options?: string[]
  required?: boolean
}

type ColumnDef = {
  title: string
  dataIndex?: string
  width?: number
  align?: 'left' | 'right' | 'center'
  ellipsis?: boolean
  render?: (v: unknown, row: Row) => ReactNode
  fixed?: 'left' | 'right'
}

type Props = {
  title: string
  description?: string
  apiPath: string
  columns: ColumnDef[]
  fields: FieldDef[]
  tabs?: { key: string; label: string; param?: string }[]
  tabParam?: string
  defaultTab?: string
  searchFields?: FieldDef[]
  showExcel?: boolean
  showDateRange?: boolean
  extraActions?: ReactNode
  onRowManage?: (row: Row) => void
  onCreate?: () => void
  hideCreate?: boolean
  fixedParams?: Record<string, string>
  createDefaults?: Record<string, unknown>
}

const { RangePicker } = DatePicker

export function HomesCrudPage({
  title, description, apiPath, columns, fields, tabs, tabParam = 'status',
  defaultTab = 'ALL', searchFields, showExcel, showDateRange, extraActions,
  onRowManage, onCreate, hideCreate, fixedParams, createDefaults }: Props) {
  const [form] = Form.useForm()
  const [editForm] = Form.useForm()
  const qc = useQueryClient()
  const [filters, setFilters] = useState<Record<string, unknown>>({
    page: 0, size: 15, [tabParam]: defaultTab, ...fixedParams })
  const [open, setOpen] = useState(false)
  const [editing, setEditing] = useState<Row | null>(null)

  const query = useQuery({
    queryKey: [apiPath, filters],
    queryFn: async () => {
      const { data } = await client.get<ApiResponse<PageResult>>(`${apiPrefix()}/${apiPath}`, { params: filters })
      return unwrap(data)
    } })

  const save = useMutation({
    mutationFn: async (values: Record<string, unknown>) => {
      const payload = { ...createDefaults, ...values, ...fixedParams }
      if (editing) {
        const { data } = await client.put(`${apiPrefix()}/${apiPath}/${editing.id}`, payload)
        return unwrap(data)
      }
      const { data } = await client.post(`${apiPrefix()}/${apiPath}`, payload)
      return unwrap(data)
    },
    onSuccess: () => {
      message.success(editing ? '수정했습니다.' : '등록했습니다.')
      setOpen(false)
      setEditing(null)
      editForm.resetFields()
      qc.invalidateQueries({ queryKey: [apiPath] })
    },
    onError: (e: Error) => message.error(e.message) })

  const remove = useMutation({
    mutationFn: async (id: number) => {
      const { data } = await client.delete(`${apiPrefix()}/${apiPath}/${id}`)
      return unwrap(data)
    },
    onSuccess: () => {
      message.success('삭제했습니다.')
      qc.invalidateQueries({ queryKey: [apiPath] })
    },
    onError: (e: Error) => message.error(e.message) })

  const openCreate = () => {
    if (onCreate) {
      onCreate()
      return
    }
    setEditing(null)
    editForm.resetFields()
    editForm.setFieldsValue(createDefaults || {})
    setOpen(true)
  }

  const openEdit = (row: Row) => {
    if (onRowManage) {
      onRowManage(row)
      return
    }
    setEditing(row)
    const vals: Record<string, unknown> = { ...row }
    fields.forEach((f) => {
      if (f.kind === 'date' && row[f.key]) vals[f.key] = dayjs(String(row[f.key]))
    })
    editForm.setFieldsValue(vals)
    setOpen(true)
  }

  const onSearch = (values: Record<string, unknown>) => {
    const dates = values.dates as [Dayjs, Dayjs] | undefined
    setFilters((prev) => ({
      ...prev,
      ...values,
      dateFrom: dates?.[0]?.format('YYYY-MM-DD'),
      dateTo: dates?.[1]?.format('YYYY-MM-DD'),
      page: 0 }))
  }

  const reset = () => {
    form.resetFields()
    setFilters({ page: 0, size: 15, [tabParam]: defaultTab, ...fixedParams })
  }

  const tableColumns = useMemo(() => [
    ...columns,
    {
      title: '관리',
      width: 110,
      fixed: 'right' as const,
      render: (_: unknown, row: Row) => (
        <Space size={4}>
          <Button size="small" type="link" onClick={() => openEdit(row)}>수정</Button>
          <Popconfirm title="삭제할까요?" onConfirm={() => remove.mutate(row.id)}>
            <Button size="small" type="link" danger icon={<DeleteOutlined />} />
          </Popconfirm>
        </Space>
      ) },
  ], [columns, remove])

  const counts = query.data?.counts

  return (
    <div className="stock-page home-sale-page">
      <div className="stock-title">
        <div>
          <h2>{title}</h2>
          {description && <p>{description}</p>}
        </div>
        <Space>
          {extraActions}
          {showExcel && (
            <Button icon={<FileExcelOutlined />} onClick={() => message.info('엑셀 다운로드(데모)')}>엑셀</Button>
          )}
          {!hideCreate && (
            <Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>등록</Button>
          )}
        </Space>
      </div>

      <Card className="stock-filter-card" size="small">
        <Form form={form} layout="inline" className="home-filter" initialValues={{ size: 15 }} onFinish={onSearch}>
          <div className="stock-filter-row">
            {showDateRange && (
              <Form.Item name="dates">
                <RangePicker className="w-230" />
              </Form.Item>
            )}
            {(searchFields || []).map((f) => (
              <Form.Item key={f.key} name={f.key}>
                {f.kind === 'select' ? (
                  <Select allowClear placeholder={f.label} className="w-130" options={options(f.options || [])} />
                ) : (
                  <Input allowClear placeholder={f.label} className="w-150" />
                )}
              </Form.Item>
            ))}
            <Form.Item name="q"><Input allowClear placeholder="검색어" className="w-160" /></Form.Item>
            <Button type="primary" htmlType="submit" icon={<SearchOutlined />}>검색</Button>
            <Button icon={<ReloadOutlined />} onClick={reset}>초기화</Button>
            <Form.Item name="size" className="sheet-size">
              <Select
                className="w-150"
                options={[15, 30, 50, 100].map((n) => ({ value: n, label: `목록 ${n}개씩 보기` }))}
                onChange={(size) => setFilters((v) => ({ ...v, size, page: 0 }))}
              />
            </Form.Item>
          </div>
        </Form>
      </Card>

      <Card className="stock-table-card" size="small">
        {tabs && (
          <Tabs
            activeKey={String(filters[tabParam] ?? defaultTab)}
            onChange={(key) => setFilters((v) => ({ ...v, [tabParam]: key, page: 0 }))}
            items={tabs.map((t) => ({
              key: t.key,
              label: counts?.[t.key] != null ? `${t.label}(${counts[t.key]})` : t.label }))}
          />
        )}
        <CareTable
          rowKey="id"
          size="small"
          loading={query.isLoading}
          dataSource={query.data?.list || []}
          columns={tableColumns}
          scroll={{ x: 1100 }}
          pagination={{
            current: Number(filters.page || 0) + 1,
            pageSize: Number(filters.size || 15),
            total: query.data?.total || 0,
            onChange: (page, size) => setFilters((v) => ({ ...v, page: page - 1, size })),
            showTotal: (t) => `총 ${t}건` }}
        />
      </Card>

      <Modal
        title={editing ? `${title} 수정` : `${title} 등록`}
        open={open}
        onCancel={() => setOpen(false)}
        onOk={() => editForm.submit()}
        confirmLoading={save.isPending}
        width={720}
        destroyOnClose
      >
        <Form
          form={editForm}
          layout="vertical"
          onFinish={(values) => {
            const payload = { ...values }
            fields.forEach((f) => {
              if (f.kind === 'date' && values[f.key]) {
                payload[f.key] = dayjs(values[f.key] as Dayjs).format('YYYY-MM-DD')
              }
            })
            save.mutate(payload)
          }}
        >
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            {fields.map((f) => (
              <Form.Item
                key={f.key}
                name={f.key}
                label={f.label}
                rules={f.required ? [{ required: true, message: `${f.label} 필수` }] : undefined}
                style={f.kind === 'textarea' ? { gridColumn: '1 / -1' } : undefined}
              >
                {f.kind === 'select' ? (
                  <Select options={options(f.options || [])} allowClear />
                ) : f.kind === 'date' ? (
                  <DatePicker style={{ width: '100%' }} />
                ) : f.kind === 'number' ? (
                  <InputNumber style={{ width: '100%' }} />
                ) : f.kind === 'textarea' ? (
                  <Input.TextArea rows={3} />
                ) : (
                  <Input />
                )}
              </Form.Item>
            ))}
          </div>
        </Form>
      </Modal>
    </div>
  )
}

export function LogPage({ title, domain }: { title: string; domain: string }) {
  return (
    <HomesCrudPage
      title={title}
      description={`${title} 처리 내역입니다.`}
      apiPath="homes/logs"
      fixedParams={{ domain }}
      showDateRange
      showExcel
      columns={[
        { title: '처리일시', dataIndex: 'processedAt', width: 160 },
        { title: '구분', dataIndex: 'action', width: 100 },
        { title: '내용', dataIndex: 'content', ellipsis: true },
        { title: '처리자', dataIndex: 'staff', width: 100 },
      ]}
      fields={[
        { key: 'action', label: '구분', kind: 'select', options: ['등록', '수정', '삭제', '정책변경'], required: true },
        { key: 'content', label: '내용', kind: 'textarea', required: true },
        { key: 'staff', label: '처리자' },
      ]}
      createDefaults={{ domain }}
    />
  )
}

export function ReportTablePage({
  title, apiPath, columns }: {
  title: string
  apiPath: string
  columns: ColumnDef[]
}) {
  const [year] = useState(dayjs().year())
  const [month, setMonth] = useState<number | undefined>(dayjs().month() + 1)
  const query = useQuery({
    queryKey: [apiPath, year, month],
    queryFn: async () => {
      const { data } = await client.get<ApiResponse<{ rows: Row[]; title?: string }>>(`${apiPrefix()}/${apiPath}`, {
        params: { year, month } })
      return unwrap(data)
    } })

  return (
    <div className="stock-page">
      <div className="stock-title">
        <div>
          <h2>{title}</h2>
          <p>{query.data?.title || title}</p>
        </div>
        <Space>
          <Select
            value={month ?? 0}
            className="w-130"
            options={[{ value: 0, label: '연간' }, ...Array.from({ length: 12 }, (_, i) => ({ value: i + 1, label: `${i + 1}월` }))]}
            onChange={(v) => setMonth(v === 0 ? undefined : v)}
          />
          <Button icon={<FileExcelOutlined />} onClick={() => message.info('엑셀 다운로드(데모)')}>엑셀</Button>
        </Space>
      </div>
      <Card size="small" className="stock-table-card">
        <CareTable
          rowKey={(r) => String(r.key ?? r.id ?? r.label)}
          size="small"
          loading={query.isLoading}
          dataSource={query.data?.rows || []}
          columns={columns}
          pagination={false}
          scroll={{ x: 900 }}
        />
      </Card>
    </div>
  )
}
