/**
 * Flights Map start page -- container component.
 *
 * Manages filter state, drives the map and calendar hooks, and renders
 * the filter panel + map canvas + loading/empty overlays.
 *
 * Uses PageLayout for the two-column layout matching the Angular version.
 *
 * @module
 */

import { type FC, lazy, Suspense, useState, useEffect, useCallback, useMemo } from "react";
import { useParams } from "@modern-js/runtime/router";
import { useTranslation } from "@/i18n/provider.js";
import { PageLayout } from "@/ui/layout/PageLayout.js";
import { PageTabs } from "@/ui/layout/PageTabs.js";
import { ClientOnly } from "./ClientOnly.js";
import { FlightsMapFilter } from "./FlightsMapFilter.js";
import { useFlightsMapSearch } from "../hooks/useFlightsMapSearch.js";
import { useFlightsMapCalendar } from "../hooks/useFlightsMapCalendar.js";
import { useGeolocationDefault } from "../hooks/useGeolocationDefault.js";
import { routesToPolylines, intermediateCityIds } from "../routesToPolylines.js";
import { filterRoutes } from "../filterRoutes.js";
import { buildBuyTicketUrl, escapeHtml } from "../buyTicketUrl.js";
import { useDictionaries, getCityCodeByAirportCode } from "@/shared/dictionaries/index.js";
import { getEnv } from "@/env/index.js";
import { getCityZoomLevel } from "../cityCategory.js";
import type {
  IFlightsMapFilterState,
  FlightsMapSearchParams,
  FlightsMapCalendarParams,
  IMapMarker,
  IMapPolyline,
  IMapPopup,
  IFlightRoute,
} from "../types.js";
import "./FlightsMapStartPage.scss";

const MapCanvas = lazy(() =>
  import("./MapCanvas.js").then((m) => ({ default: m.MapCanvas })),
);

// ---------------------------------------------------------------------------
// Date helpers
// ---------------------------------------------------------------------------

function todayYyyymmdd(): string {
  const now = new Date();
  const y = now.getFullYear().toString();
  const m = (now.getMonth() + 1).toString().padStart(2, "0");
  const d = now.getDate().toString().padStart(2, "0");
  return `${y}${m}${d}`;
}

function addMonthsYyyymmdd(base: string, months: number): string {
  const y = Number(base.slice(0, 4));
  const m = Number(base.slice(4, 6)) - 1;
  const d = Number(base.slice(6, 8));
  const date = new Date(y, m + months, d);
  const ry = date.getFullYear().toString();
  const rm = (date.getMonth() + 1).toString().padStart(2, "0");
  const rd = date.getDate().toString().padStart(2, "0");
  return `${ry}${rm}${rd}`;
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export const FlightsMapStartPage: FC = () => {
  const env = getEnv();
  const { t } = useTranslation();
  const routeParams = useParams<{ lang: string }>();
  const lang = routeParams.lang ?? "ru";

  const {
    dictionaries,
    loading: dictionariesLoading,
    error: dictionariesError,
  } = useDictionaries(lang);

  const [filterState, setFilterState] = useState<IFlightsMapFilterState>({
    connections: false,
    domestic: false,
    international: false,
  });

  useGeolocationDefault(dictionaries, filterState, setFilterState);

  const [effectiveConnections, setEffectiveConnections] = useState<0 | 1>(
    filterState.connections ? 1 : 0,
  );

  // Sync user toggle → effective.
  useEffect(() => {
    setEffectiveConnections(filterState.connections ? 1 : 0);
  }, [filterState.connections]);

  // Build search params from filter state
  const searchParams = useMemo<FlightsMapSearchParams | null>(() => {
    if (!filterState.departure) return null;

    const today = todayYyyymmdd();
    return {
      departure: filterState.departure,
      arrival: filterState.arrival,
      dateFrom: today,
      dateTo: addMonthsYyyymmdd(today, 6),
      connections: effectiveConnections,
    };
  }, [filterState.departure, filterState.arrival, effectiveConnections]);

  // Build calendar params
  const calendarParams = useMemo<FlightsMapCalendarParams | null>(() => {
    if (!filterState.departure) return null;

    const today = todayYyyymmdd();
    return {
      date: today,
      departure: filterState.departure,
      arrival: filterState.arrival,
      connections: filterState.connections,
    };
  }, [filterState.departure, filterState.arrival, filterState.connections]);

  const { routes, loading, error } = useFlightsMapSearch(searchParams);
  const { availableDays } = useFlightsMapCalendar(calendarParams);

  // Auto-fallback: empty result, route mode, connections=0 → retry with 1.
  useEffect(() => {
    if (loading || error) return;
    if (effectiveConnections !== 0) return;
    if (!filterState.departure || !filterState.arrival) return;
    if (routes.length > 0) return;
    setEffectiveConnections(1);
  }, [
    loading,
    error,
    effectiveConnections,
    filterState.departure,
    filterState.arrival,
    routes,
  ]);

  // Reflect fallback in the UI toggle once.
  useEffect(() => {
    if (effectiveConnections === 1 && !filterState.connections) {
      setFilterState((prev) => ({ ...prev, connections: true }));
    }
  }, [effectiveConnections, filterState.connections]);

  const handleFilterChange = useCallback((newState: IFlightsMapFilterState) => {
    setFilterState(newState);
  }, []);

  const handleMarkerClick = useCallback(
    (markerId: string) => {
      if (!filterState.departure) {
        setFilterState((prev): IFlightsMapFilterState => ({ ...prev, departure: markerId }));
      } else if (!filterState.arrival && markerId !== filterState.departure) {
        setFilterState((prev): IFlightsMapFilterState => ({ ...prev, arrival: markerId }));
      } else {
        setFilterState((prev): IFlightsMapFilterState => ({
          ...prev,
          departure: markerId,
          arrival: undefined,
        }));
      }
    },
    [filterState.departure, filterState.arrival],
  );

  const markers = useMemo<IMapMarker[]>(() => {
    if (!dictionaries) return [];

    return dictionaries.cities
      .filter(
        (c) =>
          typeof c.location?.lat === "number" &&
          typeof c.location?.lon === "number" &&
          Number.isFinite(c.location.lat) &&
          Number.isFinite(c.location.lon),
      )
      .map((city) => {
        const isHighlighted =
          city.code === filterState.departure ||
          city.code === filterState.arrival;
        return {
          id: city.code,
          lat: city.location.lat,
          lng: city.location.lon,
          label: city.name,
          tooltipPermanent: true,
          style: isHighlighted ? "orange" : "blue-small",
          zoomLevel: getCityZoomLevel(city.code),
          countryType: city.country_code === "RU" ? "ru" : "other",
          highlighted: isHighlighted,
        };
      });
  }, [dictionaries, filterState.departure, filterState.arrival]);

  const filteredRoutes = useMemo<IFlightRoute[]>(
    () => (dictionaries ? filterRoutes(routes, filterState, dictionaries) : []),
    [
      routes,
      filterState.domestic,
      filterState.international,
      filterState.connections,
      dictionaries,
    ],
  );

  const polylines = useMemo<IMapPolyline[]>(
    () =>
      dictionaries
        ? routesToPolylines(filteredRoutes, filterState, dictionaries)
        : [],
    [filteredRoutes, filterState.departure, filterState.arrival, dictionaries],
  );

  const intermediateIds = useMemo<string[]>(
    () => (dictionaries ? intermediateCityIds(filteredRoutes, dictionaries) : []),
    [filteredRoutes, dictionaries],
  );

  const popups = useMemo<IMapPopup[]>(() => {
    if (!dictionaries) return [];
    if (!filterState.departure || !filterState.arrival) return [];
    if (filteredRoutes.length === 0) return [];

    const first = filteredRoutes[0]!.route;
    const depCode = first[0]!;
    const arrCode = first[first.length - 1]!;

    const depCityCode = getCityCodeByAirportCode(dictionaries, depCode) ?? depCode;
    const arrCityCode = getCityCodeByAirportCode(dictionaries, arrCode) ?? arrCode;

    const depCity = dictionaries.cityByCode.get(depCityCode);
    const arrCity = dictionaries.cityByCode.get(arrCityCode);
    if (!depCity || !arrCity) return [];

    const date = filterState.date ?? todayYyyymmdd();
    const buyUrl = buildBuyTicketUrl(depCityCode, arrCityCode, date);

    const depHtml = `
    <div class="popup-header-test"><span>${escapeHtml(depCity.name)}</span></div>
  `;

    const arrHtml = `
    <div class="popup-header-test"><span>${escapeHtml(arrCity.name)}</span></div>
    <div style="text-align:center;">
      <a href="${buyUrl}" target="_blank" class="popup-buy-ticket">
        ${t("FLIGHTS-MAP.BUY-TICKET")}
      </a>
    </div>
  `;

    return [
      { lat: depCity.location.lat, lng: depCity.location.lon, content: depHtml },
      { lat: arrCity.location.lat, lng: arrCity.location.lon, content: arrHtml },
    ];
  }, [
    dictionaries,
    filterState.departure,
    filterState.arrival,
    filterState.date,
    filteredRoutes,
    t,
  ]);

  // Tile URL from env or default
  const tileUrl = `${env.API_BASE_URL}/tiles/{z}/{x}/{y}.png`;

  return (
    <div className="flights-map-start-page" data-testid="flights-map-start">
      <PageLayout
        headerLeft={
          <PageTabs viewType="flights-map" />
        }
        title={
          <h1 className="text--white page-title">
            {t("FLIGHTS-MAP.TITLE")}
          </h1>
        }
        breadcrumbs={[
          { label: t("FLIGHTS-MAP.TITLE"), url: `/${lang}/flights-map` },
        ]}
        contentLeft={
          <FlightsMapFilter
            value={filterState}
            availableDays={availableDays}
            onChange={handleFilterChange}
          />
        }
      >
        <section className="frame">
          <div className="flights-map-start__map-wrapper">
            <ClientOnly
              fallback={
                <div className="flights-map-start__spinner" aria-busy="true" data-testid="map-loading">
                  <div className="page-loader__loader">
                    <div className="loader-circle" />
                    <div className="loader-line-mask">
                      <div className="loader-line" />
                    </div>
                  </div>
                </div>
              }
            >
              <Suspense
                fallback={
                  <div className="flights-map-start__spinner" aria-busy="true" data-testid="map-loading">
                    <div className="page-loader__loader">
                      <div className="loader-circle" />
                      <div className="loader-line-mask">
                        <div className="loader-line" />
                      </div>
                    </div>
                  </div>
                }
              >
                <MapCanvas
                  markers={markers}
                  polylines={polylines}
                  popups={popups}
                  tileUrl={tileUrl}
                  onMarkerClick={handleMarkerClick}
                  className="flights-map-start__map"
                  domestic={filterState.domestic}
                  international={filterState.international}
                  intermediateIds={intermediateIds}
                />
              </Suspense>
            </ClientOnly>

            {(loading || dictionariesLoading) && (
              <div
                className="flights-map-start__loader"
                aria-busy="true"
                data-testid="map-loader"
              >
                <div className="page-loader__loader">
                  <div className="loader-circle" />
                  <div className="loader-line-mask">
                    <div className="loader-line" />
                  </div>
                </div>
              </div>
            )}

            {!loading && !dictionariesLoading && (error || dictionariesError) && (
              <div
                className="flights-map-start__error"
                role="alert"
                data-testid="map-error"
              >
                Failed to load routes. Please try again.
              </div>
            )}

            {!loading && !dictionariesLoading && !error && !dictionariesError && searchParams !== null && routes.length === 0 && (
                <div
                  className="flights-map-start__empty"
                  data-testid="map-no-directions"
                >
                  No directions found.
                </div>
              )}
          </div>
        </section>
      </PageLayout>
    </div>
  );
};
