/*
 * SCR-40 통합 일정·캘린더 (schedule). 참조: UIWS schedule/PersonalSchedulePage.
 * 월 캘린더 + 우측 선택일 어젠다/작성. 개인·부서 업무 일정(운영 SCR-15와 구분).
 * 백엔드: /api/work/schedules (fromAt/toAt ISO 범위). 색상 범례.
 */
import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { scheduleWorkApi } from '../../api/endpoints';
import type { ScheduleDto, ScheduleSaveRequest } from '../../api/types';
import { Button } from '../../components/ui/Button';
import { EmptyState, ErrorState } from '../../components/ui/States';
import { IconPlus } from '../../components/ui/icons';
import KxCalendarView, { type KxCalendarItem } from '../schedule/KxCalendarView';
import { fetchHolidaySet } from '../admin/holidayApi';
import { errMessage, fmtDateTime, useToast } from './workShared';
import './work.css';

const TYPE_COLOR: Record<string, string> = {
  milestone: '#0066B3',
  auction: '#6D4AFF',
  movein: '#0E8A5F',
  meeting: '#B45309',
  personal: '#667085',
};
const TYPE_LABEL: Record<string, string> = {
  milestone: '행사 마일스톤',
  auction: '옥션 마감',
  movein: '반입 슬롯',
  meeting: '회의',
  personal: '개인',
};

function ymd(d: Date): string {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
function colorOf(s: ScheduleDto): string {
  return s.color || TYPE_COLOR[(s.scheduleType ?? '').toLowerCase()] || '#0066B3';
}

/** 표시 월(baseDate 기준 일요일 시작 6주 그리드)의 조회 범위(yyyy-MM-dd). */
function monthRange(d: Date): { fromDate: string; toDate: string } {
  const first = new Date(d.getFullYear(), d.getMonth(), 1);
  const start = new Date(first);
  start.setDate(1 - first.getDay());
  const end = new Date(start);
  end.setDate(start.getDate() + 41);
  return { fromDate: ymd(start), toDate: ymd(end) };
}

/** ScheduleDto → KxCalendarItem(기간=시작~종료일, 유형색·라벨). startAt 없으면 제외(호출부 필터). */
function toWorkItem(s: ScheduleDto): KxCalendarItem {
  return {
    id: String(s.id),
    startDate: (s.startAt ?? '').slice(0, 10),
    endDate: (s.endAt ?? s.startAt ?? '').slice(0, 10),
    title: s.title,
    color: colorOf(s),
    badge: TYPE_LABEL[(s.scheduleType ?? '').toLowerCase()],
  };
}

export function WorkSchedulePage() {
  const qc = useQueryClient();
  const { show, node: toast } = useToast();
  const today = new Date();
  // 표시 범위(캘린더 뷰/기준일 변경 시 KxCalendarView.onRangeChange 로 갱신). 초기=이번 달 그리드.
  const [range, setRange] = useState(() => monthRange(today));
  const [selDate, setSelDate] = useState(ymd(today));
  const [composing, setComposing] = useState(false);
  const [form, setForm] = useState<ScheduleSaveRequest>({
    title: '',
    scheduleType: 'personal',
    startAt: `${ymd(today)}T09:00`,
    endAt: `${ymd(today)}T10:00`,
    allDay: false,
    location: '',
    content: '',
  });

  const listQ = useQuery({
    queryKey: ['schedules', range.fromDate, range.toDate],
    queryFn: () =>
      scheduleWorkApi.list({
        fromAt: `${range.fromDate}T00:00:00`,
        toAt: `${range.toDate}T23:59:59`,
      }),
  });

  // 공휴일 세트(캘린더 붉은색 표시) — 표시 범위별 조회. 실패해도 캘린더는 정상 동작(빈 세트).
  const holidayQ = useQuery({
    queryKey: ['holidays', range.fromDate, range.toDate],
    queryFn: () => fetchHolidaySet(range.fromDate, range.toDate),
    retry: false,
  });
  const holidays = holidayQ.data ?? new Map<string, string>();

  const byDay = useMemo(() => {
    const map = new Map<string, ScheduleDto[]>();
    for (const s of listQ.data ?? []) {
      const key = (s.startAt ?? '').slice(0, 10);
      if (!key) continue;
      const arr = map.get(key) ?? [];
      arr.push(s);
      map.set(key, arr);
    }
    return map;
  }, [listQ.data]);

  // 월/주/일 뷰 항목(기간 막대·유형색). startAt 있는 항목만.
  const calItems = useMemo(
    () => (listQ.data ?? []).filter((s) => !!(s.startAt ?? '').slice(0, 10)).map(toWorkItem),
    [listQ.data],
  );
  const legend = useMemo(
    () => Object.entries(TYPE_LABEL).map(([code, label]) => ({ code, label, color: TYPE_COLOR[code] })),
    [],
  );

  const createM = useMutation({
    mutationFn: (body: ScheduleSaveRequest) => scheduleWorkApi.create(body),
    onSuccess: () => {
      show('일정이 추가되었습니다.');
      setComposing(false);
      qc.invalidateQueries({ queryKey: ['schedules'] });
    },
    onError: (e) => show(errMessage(e)),
  });
  const delM = useMutation({
    mutationFn: (id: string) => scheduleWorkApi.remove(id),
    onSuccess: () => {
      show('삭제되었습니다.');
      qc.invalidateQueries({ queryKey: ['schedules'] });
    },
    onError: (e) => show(errMessage(e)),
  });

  const agenda = byDay.get(selDate) ?? [];

  function openCompose() {
    setForm({
      title: '',
      scheduleType: 'personal',
      startAt: `${selDate}T09:00`,
      endAt: `${selDate}T10:00`,
      allDay: false,
      location: '',
      content: '',
    });
    setComposing(true);
  }

  return (
    <div className="kx-page">
      <header className="kx-work__head">
        <div>
          <h1 className="kx-work__title">일정</h1>
          <p className="kx-work__subtitle">개인·부서 업무 일정 · 마일스톤/옥션/반입 통합 뷰 · 월/주/일</p>
        </div>
      </header>

      <div className="kx-cal">
        <div>
          <KxCalendarView
            items={calItems}
            legend={legend}
            selectedDate={selDate}
            loading={listQ.isLoading}
            holidays={holidays}
            onRangeChange={(r) => setRange(r)}
            onDateClick={(d) => setSelDate(d)}
            onItemClick={(it) => setSelDate(it.startDate)}
          />
          {listQ.isError && (
            <ErrorState message={errMessage(listQ.error)} onRetry={() => listQ.refetch()} />
          )}
        </div>

        {/* 어젠다 */}
        <aside className="kx-cal__agenda" aria-label={`${selDate} 일정`}>
          <div className="kx-detail__head">
            <h2 className="kx-detail__title">{selDate.replace(/-/g, '.')}</h2>
            <Button leadingIcon={<IconPlus size={16} />} onClick={openCompose}>
              일정 추가
            </Button>
          </div>

          {composing ? (
            <div className="kx-formgrid" style={{ gridTemplateColumns: '1fr' }}>
              <label className="kx-field">
                <span className="kx-label">제목 *</span>
                <input
                  className="kx-input"
                  value={form.title}
                  onChange={(e) => setForm({ ...form, title: e.target.value })}
                />
              </label>
              <label className="kx-field">
                <span className="kx-label">유형</span>
                <select
                  className="kx-select"
                  value={form.scheduleType ?? 'personal'}
                  onChange={(e) => setForm({ ...form, scheduleType: e.target.value })}
                >
                  {Object.entries(TYPE_LABEL).map(([k, l]) => (
                    <option key={k} value={k}>
                      {l}
                    </option>
                  ))}
                </select>
              </label>
              <label className="kx-field">
                <span className="kx-label">시작</span>
                <input
                  type="datetime-local"
                  className="kx-input"
                  value={form.startAt}
                  onChange={(e) => setForm({ ...form, startAt: e.target.value })}
                />
              </label>
              <label className="kx-field">
                <span className="kx-label">종료</span>
                <input
                  type="datetime-local"
                  className="kx-input"
                  value={form.endAt ?? ''}
                  onChange={(e) => setForm({ ...form, endAt: e.target.value })}
                />
              </label>
              <label className="kx-field">
                <span className="kx-label">장소</span>
                <input
                  className="kx-input"
                  value={form.location ?? ''}
                  onChange={(e) => setForm({ ...form, location: e.target.value })}
                />
              </label>
              <div className="kx-detail__actions">
                <Button
                  disabled={!form.title.trim() || createM.isPending}
                  onClick={() => createM.mutate(form)}
                >
                  {createM.isPending ? '저장 중…' : '저장'}
                </Button>
                <Button variant="ghost" onClick={() => setComposing(false)}>
                  취소
                </Button>
              </div>
            </div>
          ) : agenda.length === 0 ? (
            <EmptyState title="일정이 없습니다" description="이 날짜에 등록된 일정이 없습니다." />
          ) : (
            agenda.map((s) => (
              <div
                key={s.id}
                className="kx-cal__agenda-item"
                style={{ borderLeftColor: colorOf(s) }}
              >
                <div style={{ flex: 1 }}>
                  <div className="kx-list-table__title">{s.title}</div>
                  <div className="kx-detail__meta">
                    <span>{s.allDay ? '종일' : fmtDateTime(s.startAt)}</span>
                    {s.location && <span>· {s.location}</span>}
                    <span>· {TYPE_LABEL[(s.scheduleType ?? '').toLowerCase()] ?? s.scheduleType ?? ''}</span>
                  </div>
                </div>
                <button
                  className="kx-tag"
                  onClick={() => {
                    if (window.confirm('이 일정을 삭제할까요?')) delM.mutate(s.id);
                  }}
                >
                  삭제
                </button>
              </div>
            ))
          )}
        </aside>
      </div>
      {toast}
    </div>
  );
}
