"use client";

import { useReducer, useMemo, useCallback } from "react";
import { SignupModal } from "@/components/ui/SignupModal";
import { CalendarDays, Users, LayoutGrid } from "lucide-react";
import { SectionHeading } from "@/components/ui/SectionHeading";
import { Reveal } from "@/components/ui/Reveal";
import { DayCard } from "./schedule/DayCard";
import { ScheduleFilters } from "./schedule/ScheduleFilters";
import { MobileSchedule } from "./schedule/MobileSchedule";
import { GroupView } from "./schedule/GroupView";
import { buildTypeDots, shortAddress, startTimeMinutes, TIME_FILTER_EMPTY, isTimeFilterActive } from "./schedule/constants";
import type { StatusTag, TimeFilter, ScheduleDayMerged, ScheduleClassWithLocation } from "./schedule/constants";
import type { SiteContent } from "@/types/content";

type ViewMode = "days" | "groups";
type LocationMode = "all" | number;

interface ScheduleState {
  locationMode: LocationMode;
  viewMode: ViewMode;
  filterTrainerSet: Set<string>;
  filterTypes: Set<string>;
  filterStatusSet: Set<StatusTag>;
  filterLevel: string | null;
  filterTime: TimeFilter;
  filterDaySet: Set<string>;
  bookingGroup: string | null;
}

type ScheduleAction =
  | { type: "SET_LOCATION"; mode: LocationMode }
  | { type: "SET_VIEW"; mode: ViewMode }
  | { type: "TOGGLE_TRAINER"; value: string }
  | { type: "TOGGLE_TYPE"; value: string }
  | { type: "TOGGLE_STATUS"; value: StatusTag }
  | { type: "SET_LEVEL"; value: string | null }
  | { type: "SET_TIME"; value: TimeFilter }
  | { type: "TOGGLE_DAY"; day: string }
  | { type: "SET_BOOKING"; value: string | null }
  | { type: "CLEAR_FILTERS" };

const initialState: ScheduleState = {
  locationMode: "all",
  viewMode: "groups",
  filterTrainerSet: new Set(),
  filterTypes: new Set(),
  filterStatusSet: new Set(),
  filterLevel: null,
  filterTime: TIME_FILTER_EMPTY,
  filterDaySet: new Set(),
  bookingGroup: null,
};

function scheduleReducer(state: ScheduleState, action: ScheduleAction): ScheduleState {
  switch (action.type) {
    case "SET_LOCATION":
      return { ...initialState, viewMode: state.viewMode, locationMode: action.mode };
    case "SET_VIEW":
      return { ...state, viewMode: action.mode };
    case "TOGGLE_TRAINER": {
      const next = new Set(state.filterTrainerSet);
      if (next.has(action.value)) next.delete(action.value);
      else next.add(action.value);
      return { ...state, filterTrainerSet: next };
    }
    case "TOGGLE_TYPE": {
      const next = new Set(state.filterTypes);
      if (next.has(action.value)) next.delete(action.value);
      else next.add(action.value);
      return { ...state, filterTypes: next };
    }
    case "TOGGLE_STATUS": {
      const next = new Set(state.filterStatusSet);
      if (next.has(action.value)) next.delete(action.value);
      else next.add(action.value);
      return { ...state, filterStatusSet: next };
    }
    case "SET_LEVEL":
      return { ...state, filterLevel: action.value };
    case "SET_TIME":
      return { ...state, filterTime: action.value };
    case "TOGGLE_DAY": {
      const next = new Set(state.filterDaySet);
      if (next.has(action.day)) next.delete(action.day);
      else next.add(action.day);
      return { ...state, filterDaySet: next };
    }
    case "SET_BOOKING":
      return { ...state, bookingGroup: action.value };
    case "CLEAR_FILTERS":
      return { ...state, filterTrainerSet: new Set(), filterTypes: new Set(), filterStatusSet: new Set(), filterLevel: null, filterTime: TIME_FILTER_EMPTY, filterDaySet: new Set() };
  }
}

interface ScheduleProps {
  data: SiteContent["schedule"];
  scheduleConfig?: SiteContent["scheduleConfig"];
  classItems?: { name: string; color?: string }[];
  teamMembers?: { name: string; image: string }[];
}

export function Schedule({ data: schedule, scheduleConfig, classItems, teamMembers }: ScheduleProps) {
  const [state, dispatch] = useReducer(scheduleReducer, initialState);
  const { locationMode, viewMode, filterTrainerSet, filterTypes, filterStatusSet, filterLevel, filterTime, filterDaySet, bookingGroup } = state;

  const isAllMode = locationMode === "all";

  const scrollToSchedule = useCallback(() => {
    const el = document.getElementById("schedule");
    if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
  }, []);

  const toggleFilterTrainer = useCallback((value: string) => dispatch({ type: "TOGGLE_TRAINER", value }), []);
  const toggleFilterType = useCallback((value: string) => dispatch({ type: "TOGGLE_TYPE", value }), []);
  const toggleFilterStatus = useCallback((value: StatusTag) => dispatch({ type: "TOGGLE_STATUS", value }), []);
  const setFilterLevel = useCallback((value: string | null) => dispatch({ type: "SET_LEVEL", value }), []);
  const setFilterTime = useCallback((value: TimeFilter) => dispatch({ type: "SET_TIME", value }), []);

  const toggleFilterTrainerFromCard = useCallback((trainer: string | null) => {
    if (trainer) {
      dispatch({ type: "TOGGLE_TRAINER", value: trainer });
      scrollToSchedule();
    }
  }, [scrollToSchedule]);

  const toggleFilterTypeFromCard = useCallback((type: string) => {
    dispatch({ type: "TOGGLE_TYPE", value: type });
    scrollToSchedule();
  }, [scrollToSchedule]);

  const typeDots = useMemo(() => buildTypeDots(classItems), [classItems]);

  const trainerPhotos = useMemo(() => {
    const map: Record<string, string> = {};
    if (teamMembers) {
      for (const m of teamMembers) {
        if (m.image) map[m.name] = m.image;
      }
    }
    return map;
  }, [teamMembers]);

  // Build days: either from one location or merged from all
  const activeDays: ScheduleDayMerged[] = useMemo(() => {
    if (locationMode !== "all") {
      const loc = schedule.locations[locationMode];
      if (!loc) return [];
      return loc.days.map((day) => ({
        ...day,
        classes: day.classes.map((cls) => ({ ...cls })),
      }));
    }

    // Merge all locations by weekday
    const dayOrder = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"];
    const dayMap = new Map<string, ScheduleDayMerged>();

    for (const loc of schedule.locations) {
      for (const day of loc.days) {
        const existing = dayMap.get(day.day);
        const taggedClasses: ScheduleClassWithLocation[] = day.classes.map((cls) => ({
          ...cls,
          locationName: loc.name,
          locationAddress: loc.address,
        }));

        if (existing) {
          existing.classes = [...existing.classes, ...taggedClasses];
        } else {
          dayMap.set(day.day, {
            day: day.day,
            dayShort: day.dayShort,
            classes: taggedClasses,
          });
        }
      }
    }

    // Sort by weekday order
    return dayOrder
      .filter((d) => dayMap.has(d))
      .map((d) => dayMap.get(d)!);
  }, [locationMode, schedule.locations]);

  const { types, availableStatuses, levels, trainerNames } = useMemo(() => {
    const typeSet = new Set<string>();
    const levelSet = new Set<string>();
    const trainerSet = new Set<string>();
    const statusSet = new Set<string>();
    for (const day of activeDays) {
      for (const cls of day.classes) {
        typeSet.add(cls.type);
        trainerSet.add(cls.trainer);
        if (cls.status) statusSet.add(cls.status);
        if (cls.hasSlots) statusSet.add("hasSlots");
        if (cls.recruiting) statusSet.add("recruiting");
        if (cls.level) levelSet.add(cls.level);
      }
    }
    return {
      types: Array.from(typeSet).sort(),
      availableStatuses: Array.from(statusSet),
      levels: Array.from(levelSet).sort(),
      trainerNames: Array.from(trainerSet).sort(),
    };
  }, [activeDays]);

  // Parse time range for filtering
  const activeTimeRange = isTimeFilterActive(filterTime)
    ? [
        filterTime.from ? startTimeMinutes(filterTime.from) : 0,
        filterTime.to ? startTimeMinutes(filterTime.to) : 24 * 60,
      ] as const
    : null;

  const filteredDays: ScheduleDayMerged[] = useMemo(() => {
    const noFilter = filterTrainerSet.size === 0 && filterTypes.size === 0 && filterStatusSet.size === 0 && !filterLevel && !isTimeFilterActive(filterTime) && filterDaySet.size === 0;
    if (noFilter) return activeDays;

    // First filter by day names if any selected
    const dayFiltered = filterDaySet.size > 0
      ? activeDays.filter((day) => filterDaySet.has(day.day))
      : activeDays;

    return dayFiltered
      .map((day) => ({
        ...day,
        classes: day.classes.filter(
          (cls) =>
            (filterTrainerSet.size === 0 || filterTrainerSet.has(cls.trainer)) &&
            (filterTypes.size === 0 || filterTypes.has(cls.type)) &&
            (filterStatusSet.size === 0 ||
              (cls.status && filterStatusSet.has(cls.status as StatusTag)) ||
              (filterStatusSet.has("hasSlots" as StatusTag) && cls.hasSlots) ||
              (filterStatusSet.has("recruiting" as StatusTag) && cls.recruiting)) &&
            (!filterLevel || cls.level === filterLevel) &&
            (!activeTimeRange || (() => {
              const m = startTimeMinutes(cls.time);
              return m >= activeTimeRange[0] && m < activeTimeRange[1];
            })())
        ),
      }))
      .filter((day) => day.classes.length > 0);
  }, [activeDays, filterTrainerSet, filterTypes, filterStatusSet, filterLevel, filterTime, activeTimeRange, filterDaySet]);

  const hasActiveFilter = !!(filterTrainerSet.size > 0 || filterTypes.size > 0 || filterStatusSet.size > 0 || filterLevel || isTimeFilterActive(filterTime) || filterDaySet.size > 0);

  function clearFilters() {
    dispatch({ type: "CLEAR_FILTERS" });
  }

  // Available days for the day filter
  const availableDays = useMemo(() =>
    activeDays.map((d) => ({ day: d.day, dayShort: d.dayShort })),
    [activeDays]
  );

  function toggleDay(day: string) {
    dispatch({ type: "TOGGLE_DAY", day });
  }

  function switchLocation(mode: LocationMode) {
    dispatch({ type: "SET_LOCATION", mode });
  }

  const gridLayout = useMemo(() => {
    const len = filteredDays.length;
    const cls = len >= 7 ? "sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-7"
      : len >= 6 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
      : len >= 4 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5"
      : len === 3 ? "sm:grid-cols-2 lg:grid-cols-3"
      : len === 2 ? "sm:grid-cols-2"
      : "justify-items-center";
    const style = len === 1 ? undefined
      : len <= 3 && len > 0 ? { maxWidth: len * 340 + (len - 1) * 12, marginInline: "auto" as const }
      : undefined;
    return { cls, style };
  }, [filteredDays.length]);

  const activeTabClass = "bg-gold text-black shadow-[0_0_20px_rgba(201,169,110,0.3)]";
  const inactiveTabClass = "border border-neutral-300 text-neutral-500 hover:border-neutral-400 hover:text-neutral-700 dark:border-white/10 dark:text-neutral-400 dark:hover:text-white dark:hover:border-white/20";

  return (
    <section
      id="schedule"
      className="section-glow relative section-padding bg-neutral-50 dark:bg-[#050505] overflow-hidden"
    >
      <div className="section-divider absolute top-0 left-0 right-0" />

      <div className="section-container">
        <Reveal>
          <SectionHeading centered>{schedule.title}</SectionHeading>
        </Reveal>

        {/* Location tabs */}
        <Reveal>
          <div className="mt-8 flex justify-center gap-2 flex-wrap">
            {/* "All studios" tab */}
            <button
              onClick={() => switchLocation("all")}
              className={`inline-flex items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium transition-all duration-300 cursor-pointer ${
                isAllMode ? activeTabClass : inactiveTabClass
              }`}
            >
              <LayoutGrid size={14} />
              <span className="hidden sm:inline">Все студии</span>
              <span className="sm:hidden">Все</span>
            </button>

            {/* Per-location tabs */}
            {schedule.locations.map((loc, i) => (
              <button
                key={loc.name}
                onClick={() => switchLocation(i)}
                className={`inline-flex items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium transition-all duration-300 cursor-pointer ${
                  locationMode === i ? activeTabClass : inactiveTabClass
                }`}
              >
                <span className="text-center">
                  <span className="block leading-tight">{loc.name}</span>
                  {loc.address && (
                    <span className={`block text-[10px] font-normal leading-tight mt-0.5 ${
                      locationMode === i ? "text-black/60" : "text-neutral-400 dark:text-white/25"
                    }`}>
                      {shortAddress(loc.address)}
                    </span>
                  )}
                </span>
              </button>
            ))}
          </div>
        </Reveal>

        {/* View mode toggle + filter button */}
        <Reveal>
          <div className="mt-4 hidden sm:flex items-center justify-center">
            <div className="inline-flex items-center rounded-xl border border-neutral-200 bg-neutral-100 p-1 dark:border-white/[0.08] dark:bg-white/[0.04]">
              <button
                onClick={() => dispatch({ type: "SET_VIEW", mode: "days" })}
                className={`inline-flex items-center gap-1.5 rounded-lg px-4 py-2 text-xs font-medium transition-all duration-200 cursor-pointer ${
                  viewMode === "days"
                    ? "bg-white text-neutral-900 shadow-sm dark:bg-white/10 dark:text-white"
                    : "text-neutral-500 hover:text-neutral-700 dark:text-white/35 dark:hover:text-white/60"
                }`}
              >
                <CalendarDays size={13} />
                По дням
              </button>
              <button
                onClick={() => dispatch({ type: "SET_VIEW", mode: "groups" })}
                className={`inline-flex items-center gap-1.5 rounded-lg px-4 py-2 text-xs font-medium transition-all duration-200 cursor-pointer ${
                  viewMode === "groups"
                    ? "bg-white text-neutral-900 shadow-sm dark:bg-white/10 dark:text-white"
                    : "text-neutral-500 hover:text-neutral-700 dark:text-white/35 dark:hover:text-white/60"
                }`}
              >
                <Users size={13} />
                По группам
              </button>

              {/* Divider */}
              <span className="mx-1 h-5 w-px bg-white/[0.08]" />

            <ScheduleFilters
              typeDots={typeDots}
              types={types}
              availableStatuses={availableStatuses}
              levels={levels}
              filterTypes={filterTypes}
              toggleFilterType={toggleFilterType}
              filterTrainerSet={filterTrainerSet}
              toggleFilterTrainer={toggleFilterTrainer}
              filterStatusSet={filterStatusSet}
              toggleFilterStatus={toggleFilterStatus}
              filterLevel={filterLevel}
              setFilterLevel={setFilterLevel}
              filterTime={filterTime}
              setFilterTime={setFilterTime}
              availableDays={availableDays}
              filterDaySet={filterDaySet}
              toggleDay={toggleDay}
              hasActiveFilter={hasActiveFilter}
              clearFilters={clearFilters}
              trainerNames={trainerNames}
              scheduleConfig={scheduleConfig}
            />
            </div>
          </div>
        </Reveal>
      </div>

      {viewMode === "days" ? (
        <>
          {/* Mobile: compact agenda list with tap-to-filter */}
          <Reveal>
            <MobileSchedule
              typeDots={typeDots}
              filteredDays={filteredDays}
              filterTypes={filterTypes}
              toggleFilterType={toggleFilterTypeFromCard}
              filterTrainerSet={filterTrainerSet}
              toggleFilterTrainer={toggleFilterTrainerFromCard}
              hasActiveFilter={hasActiveFilter}
              clearFilters={clearFilters}
              showLocation={isAllMode}
            />
          </Reveal>

          {/* Desktop: grid layout */}
          <Reveal>
            <div
              className={`mt-8 hidden sm:grid grid-cols-1 gap-3 px-4 sm:px-6 lg:px-8 xl:px-6 ${gridLayout.cls}`}
              style={gridLayout.style}
            >
              {filteredDays.map((day) => (
                <div
                  key={day.day}
                  className={filteredDays.length === 1 ? "w-full max-w-[340px]" : ""}
                >
                  <DayCard day={day} typeDots={typeDots} showLocation={isAllMode} filterTrainerSet={filterTrainerSet} toggleFilterTrainer={toggleFilterTrainerFromCard} filterTypes={filterTypes} toggleFilterType={toggleFilterTypeFromCard} />
                </div>
              ))}

              {filteredDays.length === 0 && (
                <div className="col-span-full py-12 text-center text-sm text-neutral-400 dark:text-white/30">
                  Нет занятий по выбранным фильтрам
                </div>
              )}
            </div>
          </Reveal>
        </>
      ) : (
        /* Group view: classes clustered by trainer+type */
        <Reveal>
          <GroupView
            typeDots={typeDots}
            filteredDays={filteredDays}
            filterTypes={filterTypes}
            toggleFilterType={toggleFilterTypeFromCard}
            filterTrainerSet={filterTrainerSet}
            toggleFilterTrainer={toggleFilterTrainerFromCard}
            showLocation={isAllMode}
            onBook={(v) => dispatch({ type: "SET_BOOKING", value: v })}
            trainerPhotos={trainerPhotos}
          />
        </Reveal>
      )}
      <SignupModal
        open={bookingGroup !== null}
        onClose={() => dispatch({ type: "SET_BOOKING", value: null })}
        subtitle={bookingGroup ?? undefined}
        endpoint="/api/group-booking"
        extraBody={{ groupInfo: bookingGroup }}
      />
    </section>
  );
}
