import { useCallback, useMemo, useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { Plus } from 'lucide-react'
import { ShellTopbar } from '@/components/layout/ShellTopbar'
import { AppFooter } from '@/components/layout/AppFooter'
import { ConferenceCalendar, type CalendarViewMode } from '@/components/calendar/ConferenceCalendar'
import { ConferenceFormCard } from '@/components/calendar/ConferenceFormCard'
import { ConferenceOccurrenceDialog } from '@/components/calendar/ConferenceOccurrenceDialog'
import { useModalDismiss } from '@/hooks/useModalDismiss'
import { getCalendarOccurrences, getMyConferences, type ConferenceOut, type OccurrenceOut } from '@/api/conferences'
import { pluralizeConferences } from '@/lib/pluralize'
import '@/styles/lobby.css'
import '@/styles/calendar.css'

interface VisibleRange {
  fromIso: string
  toIso: string
}

/** Стабильный дефолт для пропса `occurrences` `ConferenceCalendar` (пока `useQuery` не загрузил данные) — см. комментарий в ConferenceCalendar.tsx про identity пропсов FullCalendar. */
const EMPTY_OCCURRENCES: OccurrenceOut[] = []

/**
 * Календарь-менеджер запланированных/закреплённых конференций
 * (см. design/mockups/calendar.html).
 *
 * Форма создания/редактирования (`ConferenceFormCard`) живёт в модалке, не в
 * сетке страницы — календарь занимает всю ширину. Клик по чипу (в т.ч. по
 * своей конференции) открывает информационное окно (`ConferenceOccurrenceDialog`);
 * редактирование — отдельное действие: карандашик на чипе (только у
 * владельца, см. `myConferenceById`) или кнопка «Редактировать» в самом
 * информационном окне.
 */
export function CalendarPage() {
  const [view, setView] = useState<CalendarViewMode>('dayGridWeek')
  const [range, setRange] = useState<VisibleRange | null>(null)
  const [isFormOpen, setIsFormOpen] = useState(false)
  const [editingConference, setEditingConference] = useState<ConferenceOut | null>(null)
  const [occurrenceDialogTarget, setOccurrenceDialogTarget] = useState<OccurrenceOut | null>(null)

  const { data: occurrences, isLoading: occurrencesLoading } = useQuery({
    queryKey: ['conferences', 'calendar', range?.fromIso, range?.toIso],
    queryFn: () => getCalendarOccurrences(range!.fromIso, range!.toIso),
    enabled: !!range,
  })

  const { data: myConferences } = useQuery({ queryKey: ['conferences', 'my'], queryFn: getMyConferences })
  const myConferenceById = useMemo(() => new Map((myConferences ?? []).map((c) => [c.id, c])), [myConferences])

  const openCreateForm = useCallback(() => {
    setEditingConference(null)
    setIsFormOpen(true)
  }, [])

  const openEditForm = useCallback((conference: ConferenceOut) => {
    setEditingConference(conference)
    setIsFormOpen(true)
    setOccurrenceDialogTarget(null)
  }, [])

  const closeForm = useCallback(() => setIsFormOpen(false), [])

  // Бэйл-аут по значению (не по ссылке): FullCalendar вызывает `datesSet`
  // повторно всякий раз, когда меняется identity его пропсов (см. подробный
  // комментарий в ConferenceCalendar.tsx). Если диапазон фактически не
  // изменился, `setRange` возвращает тот же объект — React пропускает
  // ре-рендер (Object.is-бэйлаут), и цикл не запускается даже если
  // `datesSet` дёрнется ещё раз вхолостую.
  const handleRangeChange = useCallback((fromIso: string, toIso: string) => {
    setRange((prev) => (prev && prev.fromIso === fromIso && prev.toIso === toIso ? prev : { fromIso, toIso }))
  }, [])

  const dialogOwnedConference = occurrenceDialogTarget ? myConferenceById.get(occurrenceDialogTarget.conference_id) : undefined

  return (
    <div className="page-shell">
      <ShellTopbar />
      <main className="page-main">
        <div className="page-head">
          <div>
            <h1>Календарь конференций</h1>
            <p>
              {occurrences?.length ?? 0} {pluralizeConferences(occurrences?.length ?? 0)} в выбранном периоде — запланируйте
              разовую встречу или закрепите постоянную конференцию с повторением
            </p>
          </div>
          <button type="button" className="btn btn-primary" onClick={openCreateForm}>
            <Plus style={{ width: 16, height: 16 }} aria-hidden="true" />
            Новая конференция
          </button>
        </div>

        <div className="layout-grid">
          <ConferenceCalendar
            view={view}
            onViewChange={setView}
            occurrences={occurrences ?? EMPTY_OCCURRENCES}
            isLoading={occurrencesLoading}
            myConferenceById={myConferenceById}
            onRangeChange={handleRangeChange}
            onOccurrenceClick={setOccurrenceDialogTarget}
            onEditClick={openEditForm}
          />
        </div>
      </main>
      <AppFooter />

      {isFormOpen && (
        <ConferenceFormModal
          conference={editingConference}
          onSaved={closeForm}
          onDeleted={closeForm}
          onClose={closeForm}
        />
      )}

      {occurrenceDialogTarget && (
        <ConferenceOccurrenceDialog
          occurrence={occurrenceDialogTarget}
          ownedConference={dialogOwnedConference?.is_owner ? dialogOwnedConference : undefined}
          onClose={() => setOccurrenceDialogTarget(null)}
          onEdit={openEditForm}
        />
      )}
    </div>
  )
}

interface ConferenceFormModalProps {
  conference: ConferenceOut | null
  onSaved: () => void
  onDeleted: () => void
  onClose: () => void
}

/** Модалка создания/редактирования — разметка по образцу `ConferenceOccurrenceDialog` (modal-overlay/modal-panel, закрытие по клику на оверлей, Escape и возврат фокуса). */
function ConferenceFormModal({ conference, onSaved, onDeleted, onClose }: ConferenceFormModalProps) {
  useModalDismiss(onClose)

  return (
    <div className="modal-overlay" role="dialog" aria-modal="true" onClick={onClose}>
      <div className="modal-form-wrap" onClick={(e) => e.stopPropagation()}>
        <ConferenceFormCard
          key={conference?.id ?? 'create'}
          conference={conference ?? undefined}
          onSaved={onSaved}
          onDeleted={onDeleted}
          onCancelEdit={onClose}
        />
      </div>
    </div>
  )
}
