import { useCallback, useEffect, useMemo, useState } from "react";
import { Link } from "react-router-dom";
import type { Race, RacesQuery } from "../api";
import { ApiError, getRaces } from "../api";
import { RacesCalendar } from "../components/RacesCalendar";
import {
  formatDistance,
  formatRaceDate,
  getRaceVisual,
  getRaceStatusClassName,
  getRaceStatusLabel,
  parseRaceDate,
  sortByDateAsc,
  sortByDateDesc,
} from "../lib";

const MONTH_OPTIONS: { value: string; label: string }[] = [
  { value: "", label: "Все месяцы" },
  { value: "1", label: "Январь" },
  { value: "2", label: "Февраль" },
  { value: "3", label: "Март" },
  { value: "4", label: "Апрель" },
  { value: "5", label: "Май" },
  { value: "6", label: "Июнь" },
  { value: "7", label: "Июль" },
  { value: "8", label: "Август" },
  { value: "9", label: "Сентябрь" },
  { value: "10", label: "Октябрь" },
  { value: "11", label: "Ноябрь" },
  { value: "12", label: "Декабрь" },
];

const VIEW_STORAGE_KEY = "races-view-mode";

type ViewMode = "list" | "calendar";

function yearSelectOptions(): number[] {
  const current = new Date().getFullYear();
  const start = current - 2;
  const end = current + 4;
  const years: number[] = [];
  for (let y = start; y <= end; y += 1) {
    years.push(y);
  }
  return years;
}

function getErrorMessage(error: unknown): string {
  if (error instanceof ApiError) {
    return error.message;
  }
  return "Не удалось загрузить календарь стартов.";
}

function readInitialViewMode(): ViewMode {
  try {
    const v = sessionStorage.getItem(VIEW_STORAGE_KEY);
    return v === "calendar" ? "calendar" : "list";
  } catch {
    return "list";
  }
}

function RaceList(props: { title: string; races: Race[] }): JSX.Element {
  const { title, races } = props;

  return (
    <section className="race-list" aria-label={title}>
      <h2 className="race-list__title">{title}</h2>
      {races.length > 0 ? (
        <ul className="race-list__items">
          {races.map((race) => {
            const visual = getRaceVisual(race);
            const parsedDate = parseRaceDate(race.date);
            const day = parsedDate.toLocaleDateString("ru-RU", { day: "2-digit" });
            const month = parsedDate.toLocaleDateString("ru-RU", { month: "short" });

            return (
              <li key={race.id} className={`race-card race-card--action race-card--poster race-card--${visual.variant}`}>
                <Link
                  className="race-card__link-surface"
                  to={`/races/${race.id}`}
                  aria-label={`Старт: ${race.title}`}
                >
                  <div className="race-card__image-wrap">
                    <img
                      className={`race-card__image${
                        visual.imageFit === "contain" ? " race-card__image--contain" : ""
                      }`}
                      src={visual.imageSrc}
                      alt=""
                      loading="lazy"
                      referrerPolicy="no-referrer"
                      onError={(event) => {
                        event.currentTarget.onerror = null;
                        event.currentTarget.classList.remove("race-card__image--contain");
                        event.currentTarget.src = visual.fallbackSrc;
                      }}
                    />
                    <span className="race-card__date-badge">
                      <span>{day}</span>
                      <span>{month}</span>
                    </span>
                  </div>
                  <div className="race-card__content">
                    <div className="race-card__main">
                      <p className="race-card__kicker">{visual.label}</p>
                      <p className="race-card__title">
                        <span className="race-card__title-text">{race.title}</span>
                      </p>
                      <p className="race-card__meta">
                        {formatRaceDate(race.date)} · {formatDistance(race.distanceKm)}
                      </p>
                    </div>
                    <div className="race-card__footer">
                      <span className={getRaceStatusClassName(race.status, race.date)}>
                        {getRaceStatusLabel(race.status, race.date)}
                      </span>
                      <span className="race-card__cta">Открыть</span>
                    </div>
                  </div>
                </Link>
              </li>
            );
          })}
        </ul>
      ) : (
        <p className="race-list__empty">Пока нет данных в этом разделе.</p>
      )}
    </section>
  );
}

export function RacesPage(): JSX.Element {
  const [races, setRaces] = useState<Race[]>([]);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [yearFilter, setYearFilter] = useState<string>("");
  const [monthFilter, setMonthFilter] = useState<string>("");
  const [viewMode, setViewMode] = useState<ViewMode>(() => readInitialViewMode());

  const setViewModePersist = useCallback((mode: ViewMode) => {
    setViewMode(mode);
    try {
      sessionStorage.setItem(VIEW_STORAGE_KEY, mode);
    } catch {
      /* ignore */
    }
  }, []);

  const handleViewList = useCallback(() => {
    setViewModePersist("list");
  }, [setViewModePersist]);

  const handleViewCalendar = useCallback(() => {
    setViewModePersist("calendar");
    setYearFilter((prev) => (prev === "" ? String(new Date().getFullYear()) : prev));
  }, [setViewModePersist]);

  const listQuery = useMemo((): RacesQuery | undefined => {
    if (viewMode === "calendar") {
      const y = yearFilter !== "" ? parseInt(yearFilter, 10) : new Date().getFullYear();
      if (!Number.isNaN(y)) {
        return { year: y };
      }
      return undefined;
    }
    const q: RacesQuery = {};
    if (yearFilter !== "") {
      const y = parseInt(yearFilter, 10);
      if (!Number.isNaN(y)) {
        q.year = y;
      }
    }
    if (monthFilter !== "") {
      const m = parseInt(monthFilter, 10);
      if (!Number.isNaN(m)) {
        q.month = m;
      }
    }
    return Object.keys(q).length > 0 ? q : undefined;
  }, [viewMode, yearFilter, monthFilter]);

  const displayYear = useMemo(() => {
    if (yearFilter !== "") {
      const y = parseInt(yearFilter, 10);
      return Number.isNaN(y) ? new Date().getFullYear() : y;
    }
    return new Date().getFullYear();
  }, [yearFilter]);

  useEffect(() => {
    const ac = new AbortController();
    let isMounted = true;

    async function loadRaces(): Promise<void> {
      setIsLoading(true);
      try {
        const items = await getRaces(listQuery, { signal: ac.signal });
        if (!isMounted || ac.signal.aborted) {
          return;
        }
        setRaces(items);
        setErrorMessage(null);
      } catch (error) {
        if (ac.signal.aborted || !isMounted) {
          return;
        }
        setErrorMessage(getErrorMessage(error));
      } finally {
        if (isMounted && !ac.signal.aborted) {
          setIsLoading(false);
        }
      }
    }

    void loadRaces();
    return () => {
      isMounted = false;
      ac.abort();
    };
  }, [listQuery]);

  const { upcoming, completed } = useMemo(
    () => ({
      upcoming: sortByDateAsc(races.filter((race) => race.status !== "completed")),
      completed: sortByDateDesc(races.filter((race) => race.status === "completed")),
    }),
    [races],
  );
  const statusMessage = useMemo(() => {
    if (errorMessage && !isLoading) {
      return errorMessage;
    }
    if (isLoading) {
      return "Загружаем данные...";
    }
    if (viewMode === "calendar" && monthFilter === "") {
      return "Выберите месяц, чтобы увидеть его крупным планом.";
    }
    return "";
  }, [errorMessage, isLoading, monthFilter, viewMode]);
  const statusClassName = [
    "races-status__message",
    !statusMessage ? "races-status__message--empty" : "",
    errorMessage && !isLoading ? "races-status__message--error" : "",
  ]
    .filter(Boolean)
    .join(" ");

  if (errorMessage && races.length === 0 && !isLoading) {
    return (
      <section className="page page--races" role="alert">
        <h1 className="page__title">Календарь стартов</h1>
        <p className="page__subtitle page__subtitle--error">{errorMessage}</p>
      </section>
    );
  }

  return (
    <section className="page page--races">
      <section className="races-hero" aria-label="Календарь стартов">
        <div className="races-hero__content">
          <p className="races-hero__eyebrow">Сезонная афиша</p>
          <h1 className="page__title">Календарь стартов</h1>
          <p className="page__subtitle">Будущие и прошедшие старты в одном месте.</p>
          <div className="races-view-toggle" role="group" aria-label="Вид отображения">
            <button
              type="button"
              className={`races-view-toggle__btn${viewMode === "list" ? " races-view-toggle__btn--active" : ""}`}
              onClick={handleViewList}
            >
              Список
            </button>
            <button
              type="button"
              className={`races-view-toggle__btn${viewMode === "calendar" ? " races-view-toggle__btn--active" : ""}`}
              onClick={handleViewCalendar}
            >
              Календарь
            </button>
          </div>
        </div>
        <div className="races-hero__filters">
          <div className="races-filter" role="search" aria-label="Фильтр по дате">
            <label className="races-filter__field">
              <span className="races-filter__label">Год</span>
              <select
                className="races-filter__select"
                value={viewMode === "list" ? yearFilter : yearFilter || String(displayYear)}
                onChange={(event) => {
                  setYearFilter(event.target.value);
                }}
              >
                {viewMode === "list" ? <option value="">Все года</option> : null}
                {yearSelectOptions().map((y) => (
                  <option key={y} value={String(y)}>
                    {y}
                  </option>
                ))}
              </select>
            </label>
            <label className="races-filter__field">
              <span className="races-filter__label">Месяц</span>
              <select
                className="races-filter__select"
                value={monthFilter}
                onChange={(event) => {
                  setMonthFilter(event.target.value);
                }}
              >
                {MONTH_OPTIONS.map((opt) => (
                  <option key={opt.value || "all"} value={opt.value}>
                    {opt.label}
                  </option>
                ))}
              </select>
            </label>
          </div>
        </div>
      </section>

      <div className="races-status" aria-live="polite">
        <p
          className={statusClassName}
          role={errorMessage && !isLoading ? "alert" : undefined}
          aria-busy={isLoading || undefined}
          aria-hidden={!statusMessage || undefined}
        >
          {statusMessage || "\u00a0"}
        </p>
      </div>

      {viewMode === "list" ? (
        <div className="race-lists">
          <RaceList title="Будущие" races={upcoming} />
          <RaceList title="Завершенные" races={completed} />
        </div>
      ) : (
        <div className="races-cal-wrap">
          <RacesCalendar
            displayYear={displayYear}
            monthFilter={monthFilter}
            races={races}
            onMonthFilterChange={setMonthFilter}
          />
        </div>
      )}
    </section>
  );
}
