/**
 * Calendar page — month view with toolbar, ICS controls, sharing.
 *
 * Owns the data fetching (entries + calendars + resources) for the visible
 * month and dispatches user actions to the appropriate API client call.
 */

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/Button';
import { Select } from '@/components/ui/Select';
import { EmptyState } from '@/components/ui/EmptyState';
import { MonthView } from '@/components/calendar/MonthView';
import { AppointmentModal } from '@/components/calendar/AppointmentModal';
import { IcsControls } from '@/components/calendar/IcsControls';
import { SharingSettings } from '@/components/calendar/SharingSettings';
import { TaskDetailPanel } from '@/components/calendar/TaskDetailPanel';
import { useCalendarStore } from '@/stores/calendarStore';
import {
  fetchCalendars,
  listEntries,
  updateEntry,
  type Calendar,
  type CalendarEntry,
} from '@/api/calendar';

export function CalendarPage() {
  const { t } = useTranslation();
  const {
    visibleMonth,
    goToNextMonth,
    goToPrevMonth,
    goToToday,
    activeCalendarId,
    setActiveCalendarId,
    calendars,
    setCalendars,
  } = useCalendarStore();

  const [entries, setEntries] = useState<CalendarEntry[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [modalOpen, setModalOpen] = useState(false);
  const [modalEntry, setModalEntry] = useState<CalendarEntry | null>(null);
  const [prefillDate, setPrefillDate] = useState<Date | null>(null);

  const [selectedTask, setSelectedTask] = useState<CalendarEntry | null>(null);

  // Load calendars once
  useEffect(() => {
    let cancelled = false;
    fetchCalendars()
      .then((list) => {
        if (cancelled) return;
        setCalendars(list);
        if (!activeCalendarId && list.length > 0) {
          setActiveCalendarId(list[0].id);
        }
      })
      .catch((e: Error) => {
        if (!cancelled) setError(e.message);
      });
    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Range covering the visible grid (always 6 weeks = 42 days)
  const range = useMemo(() => {
    const first = new Date(visibleMonth.getFullYear(), visibleMonth.getMonth(), 1);
    const dayOfWeek = (first.getDay() + 6) % 7;
    const start = new Date(first);
    start.setDate(first.getDate() - dayOfWeek);
    start.setHours(0, 0, 0, 0);
    const end = new Date(start);
    end.setDate(start.getDate() + 42);
    return { start, end };
  }, [visibleMonth]);

  const loadEntries = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const list = await listEntries({
        start: range.start.toISOString(),
        end: range.end.toISOString(),
      });
      setEntries(list);
    } catch (e) {
      setError((e as Error).message ?? t('calendar.errorLoad'));
    } finally {
      setLoading(false);
    }
  }, [range.start, range.end, t]);

  useEffect(() => {
    void loadEntries();
  }, [loadEntries]);

  const handleCreateAt = (date: Date) => {
    setModalEntry(null);
    setPrefillDate(date);
    setModalOpen(true);
  };

  const handleEditEntry = (entry: CalendarEntry) => {
    if (entry.entry_type === 'task') {
      setSelectedTask(entry);
      return;
    }
    setModalEntry(entry);
    setPrefillDate(null);
    setModalOpen(true);
  };

  const handleMoveEntry = async (entry: CalendarEntry, newStart: Date) => {
    try {
      const oldEnd = entry.end_at ? new Date(entry.end_at) : null;
      const oldStart = entry.start_at ? new Date(entry.start_at) : null;
      const durationMs = oldStart && oldEnd ? oldEnd.getTime() - oldStart.getTime() : 60 * 60 * 1000;
      const newEnd = new Date(newStart.getTime() + durationMs);
      const updated = await updateEntry(entry.id, {
        start_at: newStart.toISOString(),
        end_at: newEnd.toISOString(),
      });
      setEntries((cur) => cur.map((e) => (e.id === updated.id ? updated : e)));
    } catch (e) {
      setError((e as Error).message ?? t('calendar.errorSave'));
      await loadEntries();
    }
  };

  const handleSaved = (saved: CalendarEntry) => {
    setEntries((cur) => {
      const exists = cur.some((e) => e.id === saved.id);
      return exists ? cur.map((e) => (e.id === saved.id ? saved : e)) : [...cur, saved];
    });
  };

  const handleDeleted = (entryId: string) => {
    setEntries((cur) => cur.filter((e) => e.id !== entryId));
  };

  const handleTaskChanged = (updated: CalendarEntry) => {
    setSelectedTask(updated);
    setEntries((cur) => cur.map((e) => (e.id === updated.id ? updated : e)));
  };

  const activeCalendar = calendars.find((c) => c.id === activeCalendarId) ?? null;

  return (
    <div className="p-6 max-w-7xl mx-auto" data-testid="calendar-page">
      <div className="flex flex-wrap items-center justify-between gap-3 mb-4">
        <h1 className="text-2xl font-bold text-secondary-900">{t('calendar.title')}</h1>
        <div className="flex items-center gap-2">
          <Button
            variant="ghost"
            size="sm"
            onClick={goToPrevMonth}
            aria-label={t('calendar.previousMonth')}
            data-testid="calendar-prev"
          >
            ‹
          </Button>
          <Button
            variant="secondary"
            size="sm"
            onClick={goToToday}
            data-testid="calendar-today"
          >
            {t('calendar.today')}
          </Button>
          <Button
            variant="ghost"
            size="sm"
            onClick={goToNextMonth}
            aria-label={t('calendar.nextMonth')}
            data-testid="calendar-next"
          >
            ›
          </Button>
        </div>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-4">
        <div>
          {error && (
            <div
              className="mb-3 text-sm text-danger-700 bg-danger-50 border border-danger-200 rounded-md p-2"
              data-testid="calendar-error"
            >
              {error}
            </div>
          )}
          {calendars.length === 0 && !loading ? (
            <EmptyState
              title={t('calendar.noCalendars')}
              description={t('calendar.noEntries')}
              data-testid="calendar-empty"
            />
          ) : (
            <MonthView
              visibleMonth={visibleMonth}
              entries={entries}
              loading={loading}
              onCreateAt={handleCreateAt}
              onEditEntry={handleEditEntry}
              onMoveEntry={handleMoveEntry}
            />
          )}
        </div>

        <aside className="space-y-4">
          <div className="bg-white border border-secondary-200 rounded-lg p-4 space-y-3">
            <div>
              <label className="block text-xs uppercase text-secondary-500 mb-1">
                {t('calendar.appointmentCalendar')}
              </label>
              <Select
                value={activeCalendarId ?? ''}
                onChange={(e) => setActiveCalendarId(e.target.value || null)}
                options={[
                  ...calendars.map((c: Calendar) => ({ value: c.id, label: c.name })),
                ]}
                data-testid="calendar-select"
              />
            </div>
            <IcsControls
              calendar={activeCalendar}
              onImported={() => void loadEntries()}
            />
          </div>

          {activeCalendar && (
            <div className="bg-white border border-secondary-200 rounded-lg p-4">
              <SharingSettings calendar={activeCalendar} />
            </div>
          )}
        </aside>
      </div>

      <AppointmentModal
        open={modalOpen}
        onClose={() => setModalOpen(false)}
        entry={modalEntry}
        prefillDate={prefillDate}
        calendars={calendars}
        defaultCalendarId={activeCalendarId}
        onSaved={handleSaved}
        onDeleted={handleDeleted}
      />

      {selectedTask && (
        <TaskDetailPanel
          entry={selectedTask}
          onClose={() => setSelectedTask(null)}
          onChanged={handleTaskChanged}
        />
      )}
    </div>
  );
}

export default CalendarPage;
