import { useEffect, useMemo, useState } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { Button, Form, Input, TimePicker, message } from 'antd'
import Modal from './DraggableModal'
import { CloseOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons'
import dayjs, { type Dayjs } from 'dayjs'
import 'dayjs/locale/ko'
import client, { apiPrefix, unwrap, type ApiResponse } from '../api/client'

dayjs.locale('ko')

type ScheduleRow = {
  id: number
  sdate?: string
  stime?: string
  contents?: string
  displayTime?: string
}

type MonthData = {
  days?: Record<string, number>
}

const weekDays = ['일', '월', '화', '수', '목', '금', '토']

type Props = {
  open: boolean
  onClose: () => void
}

export default function SchedulePanel({ open, onClose }: Props) {
  const qc = useQueryClient()
  const [now, setNow] = useState(() => dayjs())
  const [cursor, setCursor] = useState(() => dayjs())
  const [selected, setSelected] = useState(() => dayjs())
  const [createOpen, setCreateOpen] = useState(false)
  const [form] = Form.useForm()

  useEffect(() => {
    if (!open) return
    const t = window.setInterval(() => setNow(dayjs()), 1000)
    return () => window.clearInterval(t)
  }, [open])

  useEffect(() => {
    if (open) {
      const today = dayjs()
      setNow(today)
      setCursor(today)
      setSelected(today)
    }
  }, [open])

  const selectedKey = selected.format('YYYY-MM-DD')
  const year = cursor.year()
  const month = cursor.month() + 1

  const monthQuery = useQuery({
    queryKey: ['schedules-month', year, month],
    enabled: open,
    queryFn: async () => {
      const { data } = await client.get<ApiResponse<MonthData>>(`${apiPrefix()}/schedules/month`, {
        params: { year, month },
      })
      return unwrap(data)
    },
  })

  const dayQuery = useQuery({
    queryKey: ['schedules-day', selectedKey],
    enabled: open,
    queryFn: async () => {
      const { data } = await client.get<ApiResponse<{ total: number; list: ScheduleRow[] }>>(
        `${apiPrefix()}/schedules/search`,
        { params: { sdate: selectedKey, size: 100 } },
      )
      return unwrap(data)
    },
  })

  const refresh = () => {
    qc.invalidateQueries({ queryKey: ['schedules-month'] })
    qc.invalidateQueries({ queryKey: ['schedules-day'] })
    qc.invalidateQueries({ queryKey: ['schedules'] })
  }

  const createMut = useMutation({
    mutationFn: async (values: { contents: string; stime?: Dayjs }) => {
      const body = {
        sdate: selectedKey,
        contents: values.contents,
        stime: values.stime ? values.stime.format('HH:mm') : undefined,
      }
      const { data } = await client.post(`${apiPrefix()}/schedules`, body)
      return unwrap(data)
    },
    onSuccess: () => {
      message.success('일정을 등록했습니다.')
      setCreateOpen(false)
      form.resetFields()
      refresh()
    },
    onError: (e: Error) => message.error(e.message),
  })

  const deleteMut = useMutation({
    mutationFn: async (id: number) => {
      const { data } = await client.delete(`${apiPrefix()}/schedules/${id}`)
      return unwrap(data)
    },
    onSuccess: () => {
      message.success('일정을 삭제했습니다.')
      refresh()
    },
    onError: (e: Error) => message.error(e.message),
  })

  const cells = useMemo(() => {
    const start = cursor.startOf('month')
    const startWeekday = start.day()
    const daysInMonth = cursor.daysInMonth()
    const prevMonth = cursor.subtract(1, 'month')
    const prevDays = prevMonth.daysInMonth()
    const list: { date: Dayjs; current: boolean }[] = []
    for (let i = startWeekday - 1; i >= 0; i -= 1) {
      list.push({ date: prevMonth.date(prevDays - i), current: false })
    }
    for (let d = 1; d <= daysInMonth; d += 1) {
      list.push({ date: cursor.date(d), current: true })
    }
    while (list.length % 7 !== 0) {
      const next = list[list.length - 1].date.add(1, 'day')
      list.push({ date: next, current: false })
    }
    return list
  }, [cursor])

  const eventDays = monthQuery.data?.days || {}
  const events = dayQuery.data?.list || []

  if (!open) return null

  return (
    <>
      <div className="schedule-panel-mask" onClick={onClose} />
      <aside className="schedule-panel" aria-label="일정표">
        <div className="schedule-panel-head">일정표</div>

        <div className="schedule-panel-body">
          <div className="schedule-block">
            <div className="schedule-label">TIME &amp; DATE</div>
            <div className="schedule-clock">{now.format('hh:mm:ss A')}</div>
            <div className="schedule-today">{now.format('YYYY년 MM월 DD일 dddd')}</div>
          </div>

          <div className="schedule-block">
            <div className="schedule-label">CALENDAR</div>
            <div className="schedule-calendar">
              <div className="schedule-cal-nav">
                <button type="button" onClick={() => setCursor((c) => c.subtract(1, 'month'))} aria-label="이전 달">
                  <LeftOutlined />
                </button>
                <span>{cursor.format('YYYY년 M월')}</span>
                <button type="button" onClick={() => setCursor((c) => c.add(1, 'month'))} aria-label="다음 달">
                  <RightOutlined />
                </button>
              </div>
              <div className="schedule-cal-weeks">
                {weekDays.map((d, i) => (
                  <span key={d} className={i === 0 || i === 6 ? 'weekend' : undefined}>{d}</span>
                ))}
              </div>
              <div className="schedule-cal-grid">
                {cells.map(({ date, current }) => {
                  const key = date.format('YYYY-MM-DD')
                  const isSelected = key === selectedKey
                  const isToday = key === now.format('YYYY-MM-DD')
                  const hasEvent = !!eventDays[key]
                  return (
                    <button
                      key={key}
                      type="button"
                      className={[
                        'schedule-day',
                        current ? 'current' : 'other',
                        isSelected ? 'selected' : '',
                        isToday ? 'today' : '',
                        hasEvent ? 'has-event' : '',
                      ].filter(Boolean).join(' ')}
                      onClick={() => {
                        setSelected(date)
                        if (!current) setCursor(date)
                      }}
                    >
                      {date.date()}
                    </button>
                  )
                })}
              </div>
            </div>
          </div>

          <div className="schedule-block schedule-events">
            <div className="schedule-event-head">
              <span>{selectedKey} EVENT</span>
              <span>{events.length}건</span>
            </div>
            <div className="schedule-event-list">
              {events.length === 0 ? (
                <div className="schedule-event-empty">등록된 일정이 없습니다.</div>
              ) : (
                events.map((ev) => (
                  <div key={ev.id} className="schedule-event-card">
                    <button
                      type="button"
                      className="schedule-event-del"
                      aria-label="삭제"
                      onClick={() => deleteMut.mutate(ev.id)}
                    >
                      <CloseOutlined />
                    </button>
                    <div className="schedule-event-title">{ev.contents}</div>
                    <div className="schedule-event-time">{ev.displayTime || ev.stime || '-'}</div>
                  </div>
                ))
              )}
            </div>
          </div>
        </div>

        <div className="schedule-panel-foot">
          <button
            type="button"
            className="schedule-add-btn"
            onClick={() => {
              form.setFieldsValue({ contents: undefined, stime: dayjs('09:00', 'HH:mm') })
              setCreateOpen(true)
            }}
          >
            + 일정 등록
          </button>
        </div>
      </aside>

      <Modal
        title={`${selectedKey} 일정 등록`}
        open={createOpen}
        onCancel={() => setCreateOpen(false)}
        footer={null}
        destroyOnClose
      >
        <Form form={form} layout="vertical" onFinish={(v) => createMut.mutate(v)}>
          <Form.Item name="contents" label="내용" rules={[{ required: true, message: '내용을 입력하세요.' }]}>
            <Input.TextArea rows={4} />
          </Form.Item>
          <Form.Item name="stime" label="시간">
            <TimePicker format="HH:mm" className="full-width" style={{ width: '100%' }} />
          </Form.Item>
          <div className="bbs-write-actions">
            <Button type="primary" htmlType="submit" loading={createMut.isPending}>등록</Button>
            <Button onClick={() => setCreateOpen(false)}>취소</Button>
          </div>
        </Form>
      </Modal>
    </>
  )
}
