/**
 * Shared search results page for all 4 online board search types.
 *
 * Each route page (flight, departure, arrival, route) composes this
 * component with its parsed params. This component handles:
 * - Converting parsed URL params to API search params
 * - Wiring useOnlineBoard for data fetching
 * - Wiring useLiveBoardSearch for live SignalR updates
 * - Rendering FlightList with results
 * - Navigation to flight details on card click
 *
 * @module
 */

import type { FC } from "react";
import { useCallback } from "react";
import { useNavigate, useParams } from "@modern-js/runtime/router";
import { useTranslation } from "@/i18n/provider.js";
import { FlightList } from "@/ui/flights/FlightList.js";
import { PageLayout } from "@/ui/layout/PageLayout.js";
import { PageTabs } from "@/ui/layout/PageTabs.js";
import { SearchHistory } from "@/ui/layout/SearchHistory.js";
import { OnlineBoardFilter } from "./OnlineBoardFilter.js";
import "./OnlineBoardSearchPage.scss";
import { JsonLdRenderer } from "@/shared/seo/json-ld.js";
import { useOnlineBoard } from "../hooks/useOnlineBoard.js";
import { useLiveBoardSearch } from "../hooks/useLiveBoardSearch.js";
import { useCalendarDays } from "../hooks/useCalendarDays.js";
import { buildOnlineBoardUrl } from "../url.js";
import { buildFlightListJsonLd } from "../json-ld.js";
import type { OnlineBoardParams } from "../url.js";
import type { SearchFlightsParams, CalendarParams } from "../api.js";
import type { FlightRequestType, ISimpleFlight } from "../types.js";

export interface OnlineBoardSearchPageProps {
  /** Parsed and validated URL params from the route */
  params: OnlineBoardParams & { type: "flight" | "departure" | "arrival" | "route" };
}

/**
 * Format a yyyyMMdd date string for display in the calendar strip.
 * Shows the day number (e.g. "15", "16").
 */
function formatDayLabel(yyyymmdd: string): string {
  if (yyyymmdd.length !== 8) return yyyymmdd;
  const day = parseInt(yyyymmdd.slice(6, 8), 10);
  return String(day);
}

/**
 * Convert yyyyMMdd URL date to API format (yyyy-MM-ddT00:00:00).
 */
function formatDateForApi(yyyymmdd: string): string {
  if (yyyymmdd.length === 8) {
    const y = yyyymmdd.slice(0, 4);
    const m = yyyymmdd.slice(4, 6);
    const d = yyyymmdd.slice(6, 8);
    return `${y}-${m}-${d}T00:00:00`;
  }
  // Already in ISO-ish format
  return yyyymmdd.includes("T") ? yyyymmdd : `${yyyymmdd}T00:00:00`;
}

/**
 * Convert parsed online board URL params into API search params.
 * The API expects dateFrom/dateTo in yyyy-MM-ddT00:00:00 format.
 */
function toSearchParams(
  params: OnlineBoardSearchPageProps["params"],
): SearchFlightsParams {
  const apiDate = formatDateForApi(params.date);
  const base: SearchFlightsParams = {
    dateFrom: apiDate,
    dateTo: apiDate,
  };

  switch (params.type) {
    case "flight":
      base.flightNumber = `${params.carrier}${params.flightNumber}`;
      break;
    case "departure":
      base.departure = params.station;
      break;
    case "arrival":
      base.arrival = params.station;
      break;
    case "route":
      base.departure = params.departure;
      base.arrival = params.arrival;
      break;
  }

  if ("timeFrom" in params && params.timeFrom) {
    base.timeFrom = params.timeFrom;
  }
  if ("timeTo" in params && params.timeTo) {
    base.timeTo = params.timeTo;
  }

  return base;
}

/**
 * Convert parsed params into calendar API params.
 */
function toCalendarParams(
  params: OnlineBoardSearchPageProps["params"],
): CalendarParams {
  const base: CalendarParams = {
    date: formatDateForApi(params.date),
    searchType: params.type as FlightRequestType,
  };

  switch (params.type) {
    case "flight":
      base.flightNumber = `${params.carrier}${params.flightNumber}`;
      break;
    case "departure":
      base.departure = params.station;
      break;
    case "arrival":
      base.arrival = params.station;
      break;
    case "route":
      base.departure = params.departure;
      base.arrival = params.arrival;
      break;
  }

  return base;
}

/**
 * Extract live board channel params from parsed URL params.
 */
function toLiveBoardParams(
  params: OnlineBoardSearchPageProps["params"],
): { date: string; departure?: string; arrival?: string } {
  const result: { date: string; departure?: string; arrival?: string } = {
    date: params.date,
  };

  switch (params.type) {
    case "departure":
      result.departure = params.station;
      break;
    case "arrival":
      result.arrival = params.station;
      break;
    case "route":
      result.departure = params.departure;
      result.arrival = params.arrival;
      break;
  }

  return result;
}

/**
 * Shared search results page composed by all 4 search route pages.
 */
export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
  params,
}) => {
  const navigate = useNavigate();
  const { t } = useTranslation();
  const routeParams = useParams<{ lang: string }>();
  const lang = routeParams.lang ?? "ru";

  // Data fetching
  const searchParams = toSearchParams(params);
  const { flights, loading, error, refresh } = useOnlineBoard(searchParams);

  // Live updates via SignalR
  const liveBoardParams = toLiveBoardParams(params);
  const { flights: liveFlights, connectionStatus } = useLiveBoardSearch(
    liveBoardParams,
    flights,
  );

  // Calendar days
  const calendarParams = toCalendarParams(params);
  const { days: calendarDays } = useCalendarDays(calendarParams);

  // Navigation: click a flight to go to details
  const handleFlightClick = useCallback(
    (flight: ISimpleFlight) => {
      const detailsParams: OnlineBoardParams = flight.flightId.suffix
        ? {
            type: "details",
            carrier: flight.flightId.carrier,
            flightNumber: flight.flightId.flightNumber,
            suffix: flight.flightId.suffix,
            date: flight.flightId.date,
          }
        : {
            type: "details",
            carrier: flight.flightId.carrier,
            flightNumber: flight.flightId.flightNumber,
            date: flight.flightId.date,
          };
      const detailsUrl = buildOnlineBoardUrl(detailsParams);
      void navigate(`/${lang}/${detailsUrl}`);
    },
    [navigate, lang],
  );

  // Navigation: change date via calendar
  const handleDateChange = useCallback(
    (newDate: string) => {
      const newParams = { ...params, date: newDate };
      const url = buildOnlineBoardUrl(newParams);
      void navigate(`/${lang}/${url}`);
    },
    [navigate, lang, params],
  );

  // Use live flights when connected, otherwise fetched flights
  const displayFlights = connectionStatus === "live" ? liveFlights : flights;

  // JSON-LD for search results (rendered once we have flights)
  const searchDescription = `Online board ${params.type} search results`;
  const jsonLd = displayFlights.length > 0
    ? buildFlightListJsonLd(displayFlights, searchDescription)
    : undefined;

  return (
    <div className="online-board-search" data-testid="online-board-search">
      {jsonLd && <JsonLdRenderer data={jsonLd} />}
      <PageLayout
        headerLeft={<PageTabs viewType="onlineboard" />}
        title={
          <h1 className="text--white page-title">
            {t("BOARD.TITLE")}
          </h1>
        }
        breadcrumbs={[
          { label: t("BOARD.TITLE"), url: `/${lang}/onlineboard` },
        ]}
        contentLeft={
          <>
            <OnlineBoardFilter
              {...(params.type === "route"
                ? {
                    initialDeparture: params.departure,
                    initialArrival: params.arrival,
                    initialDate: params.date,
                    initialTab: "route" as const,
                  }
                : params.type === "departure"
                  ? {
                      initialDeparture: params.station,
                      initialDate: params.date,
                      initialTab: "route" as const,
                    }
                  : params.type === "arrival"
                    ? {
                        initialArrival: params.station,
                        initialDate: params.date,
                        initialTab: "route" as const,
                      }
                    : params.type === "flight"
                      ? {
                          initialFlightNumber: params.flightNumber,
                          initialDate: params.date,
                          initialTab: "flight" as const,
                        }
                      : {})}
            />
            <SearchHistory />
          </>
        }
        stickyContent={
          calendarDays.length > 0 ? (
            <div className="online-board-search__calendar" data-testid="calendar-strip">
              {calendarDays.map((day) => (
                <button
                  key={day}
                  type="button"
                  className={`calendar-day${day === params.date ? " calendar-day--active" : ""}`}
                  onClick={() => handleDateChange(day)}
                >
                  {formatDayLabel(day)}
                </button>
              ))}
            </div>
          ) : undefined
        }
      >
        {/* Connection status indicator */}
        <div className="online-board-search__status" data-testid="connection-status">
          {connectionStatus === "live" && (
            <span className="connection-badge connection-badge--live">Live</span>
          )}
          {connectionStatus === "reconnecting" && (
            <span className="connection-badge connection-badge--reconnecting">Reconnecting...</span>
          )}
          {connectionStatus === "offline" && (
            <span className="connection-badge connection-badge--offline">Offline</span>
          )}
        </div>

        {/* Error state */}
        {error && (
          <section className="frame" data-testid="search-error">
            <div className="online-board-search__error-card">
              <h3 className="online-board-search__error-title">
                Не удалось загрузить данные
              </h3>
              <p className="online-board-search__error-message">
                API сервер недоступен. Проверьте подключение и попробуйте снова.
              </p>
              <button
                type="button"
                className="online-board-search__retry-btn"
                onClick={refresh}
              >
                Повторить
              </button>
            </div>
          </section>
        )}

        {/* Flight list */}
        {!error && <FlightList flights={displayFlights} loading={loading} />}

        {/* Flight click overlay — we make the list clickable */}
        {!loading && displayFlights.length > 0 && (
          <div className="online-board-search__actions" data-testid="flight-actions">
            {displayFlights.map((flight) => (
              <button
                key={flight.id}
                type="button"
                className="flight-detail-link"
                data-testid={`flight-link-${flight.id}`}
                onClick={() => handleFlightClick(flight)}
              >
                View details for {flight.flightId.carrier} {flight.flightId.flightNumber}
              </button>
            ))}
          </div>
        )}
      </PageLayout>
    </div>
  );
};
