'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { ComponentType } from 'react';
import FullCalendarBase from '@fullcalendar/react';
import type { DateSelectArg, DatesSetArg, EventClickArg, EventContentArg, EventInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import trLocale from '@fullcalendar/core/locales/tr.js';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import {
  MealTagInput,
  type MealTagInputHandle,
  joinMealTags,
  tagsFromStoredValue,
} from '@/components/school/meal-tag-input';
import { apiFetchJson } from '@/lib/auth';
import { useBranches } from '@/lib/hooks/use-branches';
import { SelectNative } from '@/components/ui/select-native';

const FullCalendar = FullCalendarBase as unknown as ComponentType<Record<string, unknown>>;

type ApiMealMenu = {
  id: string;
  menuDate: string;
  branchId: string | null;
  breakfast: string | null;
  lunch: string | null;
  afternoonSnack: string | null;
};

type UpsertMealMenuResponse = ApiMealMenu | { deleted: true; menuDate: string };

interface MealCalendarEvent extends EventInput {
  id: string;
  extendedProps: {
    breakfast: string;
    lunch: string;
    afternoonSnack: string;
  };
}

function toYmdLocal(d: Date): string {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${day}`;
}

function defaultVisibleRange(): { from: string; to: string } {
  const n = new Date();
  const from = new Date(n.getFullYear(), n.getMonth() - 1, 1);
  const to = new Date(n.getFullYear(), n.getMonth() + 2, 0);
  return { from: toYmdLocal(from), to: toYmdLocal(to) };
}

const EVENT_TONE_COUNT = 8;

function eventToneIndex(id: string): number {
  let h = 2166136261;
  for (let i = 0; i < id.length; i += 1) {
    h ^= id.charCodeAt(i);
    h = Math.imul(h, 16777619);
  }
  return Math.abs(h >>> 0) % EVENT_TONE_COUNT;
}

function menuTitle(m: ApiMealMenu): string {
  const parts: string[] = [];
  if (m.breakfast?.trim()) parts.push('K');
  if (m.lunch?.trim()) parts.push('Ö');
  if (m.afternoonSnack?.trim()) parts.push('İ');
  return parts.length ? `Menü (${parts.join(' · ')})` : 'Menü';
}

function menuRowToFcEvent(m: ApiMealMenu): MealCalendarEvent {
  return {
    id: m.id,
    title: menuTitle(m),
    start: m.menuDate,
    allDay: true,
    backgroundColor: 'transparent',
    borderColor: 'transparent',
    textColor: 'inherit',
    extendedProps: {
      breakfast: m.breakfast ?? '',
      lunch: m.lunch ?? '',
      afternoonSnack: m.afternoonSnack ?? '',
    },
  };
}

function renderEventContent(eventInfo: EventContentArg) {
  const id = String(eventInfo.event.id ?? '');
  const tone = eventToneIndex(id);
  return (
    <div className={`calendar-event-pill calendar-event-tone-${tone} fc-event-main`}>
      <span className="calendar-event-accent" aria-hidden />
      <div className="calendar-event-body">
        {eventInfo.timeText ? <span className="calendar-event-time">{eventInfo.timeText}</span> : null}
        <span className="calendar-event-title">{eventInfo.event.title}</span>
      </div>
    </div>
  );
}

export function SchoolMealsCalendar() {
  const { branches } = useBranches();
  const [branchId, setBranchId] = useState('');
  const [menus, setMenus] = useState<ApiMealMenu[]>([]);
  const [visibleRange, setVisibleRange] = useState(defaultVisibleRange);
  const [loading, setLoading] = useState(false);
  const [listError, setListError] = useState('');
  const [open, setOpen] = useState(false);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [menuDate, setMenuDate] = useState('');
  const [breakfastTags, setBreakfastTags] = useState<string[]>([]);
  const [lunchTags, setLunchTags] = useState<string[]>([]);
  const [snackTags, setSnackTags] = useState<string[]>([]);
  const [saving, setSaving] = useState(false);
  const [formError, setFormError] = useState('');
  const breakfastRef = useRef<MealTagInputHandle>(null);
  const lunchRef = useRef<MealTagInputHandle>(null);
  const snackRef = useRef<MealTagInputHandle>(null);

  const events = useMemo(() => menus.map(menuRowToFcEvent), [menus]);

  const loadMenus = useCallback(async () => {
    setLoading(true);
    setListError('');
    const q = new URLSearchParams({
      from: visibleRange.from,
      to: visibleRange.to,
    });
    if (branchId) q.set('branchId', branchId);
    const res = await apiFetchJson<ApiMealMenu[]>(`/v1/admin/meal-menus?${q.toString()}`);
    if (res.error) {
      setListError(res.error);
      setMenus([]);
    } else {
      setMenus(Array.isArray(res.data) ? res.data : []);
    }
    setLoading(false);
  }, [visibleRange.from, visibleRange.to, branchId]);

  useEffect(() => {
    loadMenus();
  }, [loadMenus]);

  const onDatesSet = useCallback((arg: DatesSetArg) => {
    const from = toYmdLocal(arg.start);
    const endExclusive = arg.end;
    const lastVisible = new Date(endExclusive);
    lastVisible.setDate(lastVisible.getDate() - 1);
    const to = toYmdLocal(lastVisible);
    setVisibleRange({ from, to });
  }, []);

  const resetForm = useCallback(() => {
    setSelectedId(null);
    setMenuDate('');
    setBreakfastTags([]);
    setLunchTags([]);
    setSnackTags([]);
    setFormError('');
  }, []);

  const openForDate = useCallback(
    (ymd: string, row?: ApiMealMenu | null) => {
      resetForm();
      setMenuDate(ymd);
      if (row) {
        setSelectedId(row.id);
        setBreakfastTags(tagsFromStoredValue(row.breakfast));
        setLunchTags(tagsFromStoredValue(row.lunch));
        setSnackTags(tagsFromStoredValue(row.afternoonSnack));
      }
      setOpen(true);
    },
    [resetForm],
  );

  const handleDateSelect = useCallback(
    (selectInfo: DateSelectArg) => {
      const ymd = selectInfo.startStr;
      const existing = menus.find((m) => m.menuDate === ymd) ?? null;
      openForDate(ymd, existing);
      selectInfo.view.calendar.unselect();
    },
    [menus, openForDate],
  );

  const handleEventClick = useCallback(
    (clickInfo: EventClickArg) => {
      const id = String(clickInfo.event.id);
      const row = menus.find((m) => m.id === id);
      if (!row) return;
      openForDate(row.menuDate, row);
    },
    [menus, openForDate],
  );

  const handleSave = useCallback(async () => {
    if (!menuDate) return;
    const bTags = breakfastRef.current?.flush() ?? breakfastTags;
    const lTags = lunchRef.current?.flush() ?? lunchTags;
    const sTags = snackRef.current?.flush() ?? snackTags;
    setSaving(true);
    setFormError('');
    const res = await apiFetchJson<UpsertMealMenuResponse>('/v1/admin/meal-menus', {
      method: 'POST',
      body: JSON.stringify({
        menuDate,
        branchId: branchId || undefined,
        breakfast: bTags.length ? joinMealTags(bTags) : undefined,
        lunch: lTags.length ? joinMealTags(lTags) : undefined,
        afternoonSnack: sTags.length ? joinMealTags(sTags) : undefined,
      }),
    });
    setSaving(false);
    if (res.error) {
      setFormError(res.error);
      return;
    }
    setOpen(false);
    resetForm();
    await loadMenus();
  }, [menuDate, branchId, breakfastTags, lunchTags, snackTags, resetForm, loadMenus]);

  const handleDelete = useCallback(async () => {
    if (!selectedId) return;
    setSaving(true);
    setFormError('');
    const res = await apiFetchJson(`/v1/admin/meal-menus/${selectedId}`, { method: 'DELETE' });
    setSaving(false);
    if (res.error) {
      setFormError(res.error);
      return;
    }
    setOpen(false);
    resetForm();
    await loadMenus();
  }, [selectedId, resetForm, loadMenus]);

  return (
    <>
      <div className="border-b border-gray-200 px-4 py-4 dark:border-gray-800 sm:px-6">
        <div className="flex flex-wrap items-end gap-3">
          {branches.length > 0 && (
            <div className="min-w-[200px] space-y-1">
              <Label className="text-sm text-zinc-600 dark:text-zinc-400">Şube</Label>
              <SelectNative
                className="h-11 w-full min-w-[180px] rounded-lg sm:max-w-xs"
                value={branchId}
                onChange={(e) => setBranchId(e.target.value)}
              >
                <option value="">Tüm şubeler</option>
                {branches.map((b) => (
                  <option key={b.id} value={b.id}>
                    {b.name}
                  </option>
                ))}
              </SelectNative>
            </div>
          )}
          {loading ? (
            <span className="pb-2 text-sm text-gray-500 dark:text-gray-400">Yükleniyor…</span>
          ) : null}
        </div>
        {listError ? <p className="mt-2 text-sm text-red-600 dark:text-red-400">{listError}</p> : null}
        <p className="mt-2 text-sm text-gray-500 dark:text-gray-400">
          Takvimde bir güne tıklayarak kahvaltı, öğle ve ikindi menüsünü girin.
          {branchId
            ? ` Seçili şube: ${branches.find((b) => b.id === branchId)?.name ?? ''}`
            : ' Şube seçilmezse menü tüm kurum için uygulanır.'}
        </p>
      </div>

      <div className="custom-calendar">
        <FullCalendar
          plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
          initialView="dayGridMonth"
          locale={trLocale}
          headerToolbar={{
            left: 'prev,next',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay',
          }}
          buttonText={{
            today: 'bugün',
            month: 'ay',
            week: 'hafta',
            day: 'gün',
          }}
          titleFormat={{ year: 'numeric', month: 'long' }}
          events={events}
          selectable
          selectMirror
          select={handleDateSelect}
          eventClick={handleEventClick}
          eventContent={renderEventContent}
          datesSet={onDatesSet}
          height="auto"
        />
      </div>

      <Dialog
        open={open}
        onOpenChange={(next) => {
          setOpen(next);
          if (!next) resetForm();
        }}
      >
        <DialogContent className="max-w-[700px] gap-0 p-6 sm:p-8">
          <DialogHeader className="space-y-2 text-left">
            <DialogTitle className="text-xl dark:text-white">
              {selectedId ? 'Menüyü düzenle' : 'Menü ekle'}
            </DialogTitle>
            <DialogDescription className="text-sm text-gray-500 dark:text-gray-400">
              Her öğün için yemek adlarını yazıp Enter veya virgül ile etiket olarak ekleyin. Üç öğün de boşken
              kayıt silinir.
            </DialogDescription>
          </DialogHeader>

          <div className="mt-6 space-y-5">
            {formError ? (
              <div className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/40 dark:text-red-200">
                {formError}
              </div>
            ) : null}

            <div className="space-y-1.5">
              <Label htmlFor="meal-date">Tarih</Label>
              <Input
                id="meal-date"
                type="date"
                value={menuDate}
                onChange={(e) => setMenuDate(e.target.value)}
                className="h-11"
                disabled={!!selectedId}
              />
              {selectedId ? (
                <p className="text-xs text-gray-500 dark:text-gray-500">Tarih yalnızca yeni menüde değiştirilebilir.</p>
              ) : null}
            </div>

            <MealTagInput
              ref={breakfastRef}
              id="meal-breakfast"
              label="Kahvaltı"
              tags={breakfastTags}
              onTagsChange={setBreakfastTags}
              placeholder="Örn. peynir"
              disabled={saving}
            />

            <MealTagInput
              ref={lunchRef}
              id="meal-lunch"
              label="Öğle yemeği"
              tags={lunchTags}
              onTagsChange={setLunchTags}
              placeholder="Örn. çorba"
              disabled={saving}
            />

            <MealTagInput
              ref={snackRef}
              id="meal-snack"
              label="İkindi yemeği"
              tags={snackTags}
              onTagsChange={setSnackTags}
              placeholder="Örn. meyve"
              disabled={saving}
            />
          </div>

          <DialogFooter className="mt-8 flex-col gap-2 sm:flex-row sm:justify-between">
            <div>
              {selectedId ? (
                <Button
                  type="button"
                  variant="secondary"
                  className="text-red-600 hover:bg-red-50 dark:hover:bg-red-950/40"
                  onClick={() => void handleDelete()}
                  disabled={saving}
                >
                  Sil
                </Button>
              ) : (
                <span />
              )}
            </div>
            <div className="flex flex-col gap-2 sm:flex-row">
              <Button type="button" variant="secondary" onClick={() => setOpen(false)} disabled={saving}>
                Vazgeç
              </Button>
              <Button type="button" onClick={() => void handleSave()} disabled={!menuDate || saving}>
                {saving ? 'Kaydediliyor…' : 'Kaydet'}
              </Button>
            </div>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
