/**
 * Schedule-specific expanded body for a flight card.
 *
 * Mirrors Angular's `connecting-flight-body` / `multi-flight-body`
 * layout: each leg is rendered as a `flight-body-part-header` row
 * (section number, flight number, operator logo + aircraft model,
 * scheduled departure time, departure station, leg duration, arrival
 * time, arrival station). Between legs, a `transfer-inline-extended`
 * box shows the connection icon + ground time + departure/arrival
 * airports of the transfer.
 *
 * The synthetic MultiLeg from `extractSimpleFlights` carries
 * `_childFlightIds` so connecting flights show two distinct flight
 * numbers (`SU 6188` / `SU 6233`) over their respective legs. For
 * true MultiLeg flights all leg headers reuse the parent flight ID.
 *
 * @module
 */

import type { FC } from "react";
import { useTranslation } from "@/i18n/provider.js";
import { useLocale } from "@/i18n/useLocale.js";
import type {
  IFlightLeg,
  ISimpleFlight,
} from "@/features/online-board/types.js";
import { operatingCarrier } from "@/features/online-board/types.js";
import { resolveCarrierByFlightNumber } from "@/shared/operatorIcon.js";
import { TimeGroup } from "@/ui/flights/TimeGroup.js";
import { StationDisplay } from "@/ui/flights/StationDisplay.js";
import { OperatorLogo } from "@/ui/flights/OperatorLogo.js";
import { FlightActions } from "@/features/online-board/components/BoardDetailsHeader/FlightActions.js";
import "./ScheduleFlightBody.scss";

export interface ScheduleFlightBodyProps {
  flight: ISimpleFlight;
  /**
   * Render the share/buy/register/status action strip at the bottom of
   * the body — mirrors Angular's `flight-details-body-actions` on the
   * schedule search results page. Off by default so the schedule
   * details page (which owns its own page-level summary actions) stays
   * unchanged.
   */
  showActions?: boolean;
  /** Locale used to build the buy-ticket URL when `showActions` is true. */
  locale?: string;
  /**
   * Callback fired when the user clicks the flight details button.
   * Mirrors Angular's `flight-details-body-actions` → `flight-actions`
   * → `flight-details-button` → `toDetails` event.
   */
  onFlightDetails?: (flight: ISimpleFlight) => void;
}

interface ChildFlightId {
  carrier: string;
  flightNumber: string;
  suffix?: string;
}

/** Convert "HH:MM:SS" or "PT1H30M" into Angular `DurationPipe` output. */
function formatDuration(value: string | undefined, language: string): string {
  if (!value) return "";
  const isRu = language.startsWith("ru");
  let h = 0;
  let m = 0;
  const hms = /^(\d+):(\d+):(\d+)$/.exec(value);
  if (hms) {
    h = parseInt(hms[1] ?? "0", 10);
    m = parseInt(hms[2] ?? "0", 10);
  } else {
    const iso = /^PT(?:(\d+)H)?(?:(\d+)M)?/.exec(value);
    if (iso) {
      h = parseInt(iso[1] ?? "0", 10);
      m = parseInt(iso[2] ?? "0", 10);
    } else {
      return value;
    }
  }
  return isRu ? `${h}ч. ${m}мин.` : `${h}h ${m}m`;
}

/**
 * Compute ground-transfer duration string between two consecutive legs.
 * Uses UTC timestamps (not local, which lack timezone) for correct diff.
 * TZ §4.1.16.7: duration = departure UTC − arrival UTC.
 */
function transferDuration(prev: IFlightLeg, next: IFlightLeg): string {
  const prevArr = prev.arrival.times.scheduledArrival.utc;
  const nextDep = next.departure.times.scheduledDeparture.utc;
  if (!prevArr || !nextDep) return "";
  const a = new Date(prevArr).getTime();
  const b = new Date(nextDep).getTime();
  if (Number.isNaN(a) || Number.isNaN(b) || b <= a) return "";
  const minutes = Math.round((b - a) / 60000);
  const h = Math.floor(minutes / 60);
  const m = minutes % 60;
  return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:00`;
}

export const ScheduleFlightBody: FC<ScheduleFlightBodyProps> = ({
  flight,
  showActions = false,
  locale = "ru-ru",
  onFlightDetails,
}) => {
  const { t } = useTranslation();
  const { language } = useLocale();

  const legs: IFlightLeg[] =
    flight.routeType === "Direct" ? [flight.leg] : flight.legs;
  if (legs.length === 0) return null;

  const childFlightIds = (flight as ISimpleFlight & {
    _childFlightIds?: ChildFlightId[];
  })._childFlightIds;
  const isConnecting = Boolean(childFlightIds && childFlightIds.length > 1);
  const parentFlightId = flight.flightId;

  /** Pick the flight ID to display per leg. */
  const flightIdForLeg = (legIndex: number): ChildFlightId => {
    if (childFlightIds && childFlightIds.length > 0) {
      const id =
        childFlightIds[Math.min(legIndex, childFlightIds.length - 1)];
      if (id) return id;
    }
    return parentFlightId;
  };

  // Angular renders a horizontal `timeline` summary above the per-leg
  // cards: dep-time → [section# / leg-duration] → arr-time → ground-
  // time → next-dep-time → [section# / next-leg-duration] → final
  // arr-time, with a station row underneath. Only worth rendering for
  // multi-leg routes.
  const showTimeline = legs.length > 1;

  return (
    <div className="schedule-flight-body" data-testid="schedule-flight-body">
      {showTimeline && (
        <div
          className="schedule-flight-body__timeline"
          data-testid="schedule-timeline"
        >
          <div className="schedule-flight-body__timeline-row">
            {legs.map((leg, i) => (
              <span key={`tl-leg-${i}`} className="schedule-flight-body__timeline-leg">
                <span className="schedule-flight-body__timeline-time">
                  <TimeGroup
                    scheduled={leg.departure.times.scheduledDeparture.local}
                  />
                </span>
                <span className="schedule-flight-body__timeline-section">
                  <span className="schedule-flight-body__timeline-bar" />
                  <span className="schedule-flight-body__timeline-section-num">
                    {i + 1}
                  </span>
                  <span className="schedule-flight-body__timeline-section-dur">
                    {formatDuration(leg.flyingTime, language)}
                  </span>
                  <span className="schedule-flight-body__timeline-bar" />
                </span>
                <span className="schedule-flight-body__timeline-time">
                  <TimeGroup
                    scheduled={leg.arrival.times.scheduledArrival.local}
                  />
                </span>
                {(() => {
                  const next = legs[i + 1];
                  if (!next) return null;
                  return (
                    <span className="schedule-flight-body__timeline-transit">
                      {formatDuration(transferDuration(leg, next), language)}
                    </span>
                  );
                })()}
              </span>
            ))}
          </div>
          <div className="schedule-flight-body__timeline-stations">
            {legs.map((leg, i) => (
              <span
                key={`tl-st-${i}`}
                className="schedule-flight-body__timeline-station"
              >
                <span className="schedule-flight-body__timeline-station-city">
                  {leg.departure.scheduled.city}
                </span>
                {leg.departure.terminal && (
                  <span className="schedule-flight-body__timeline-station-terminal">
                    {[leg.departure.scheduled.airport, leg.departure.terminal]
                      .filter(Boolean)
                      .join(" - ")}
                  </span>
                )}
              </span>
            ))}
            {(() => {
              const lastLeg = legs[legs.length - 1];
              if (!lastLeg) return null;
              const arrival = lastLeg.arrival;
              return (
                <span className="schedule-flight-body__timeline-station">
                  <span className="schedule-flight-body__timeline-station-city">
                    {arrival.scheduled.city}
                  </span>
                  {arrival.terminal && (
                    <span className="schedule-flight-body__timeline-station-terminal">
                      {[arrival.scheduled.airport, arrival.terminal]
                        .filter(Boolean)
                        .join(" - ")}
                    </span>
                  )}
                </span>
              );
            })()}
          </div>
        </div>
      )}
      {legs.map((leg, idx) => {
        const id = flightIdForLeg(idx);
        // TZ §4.1.22: range-based fallback when OperatingBy is null (SU flights only).
        const carrier =
          operatingCarrier(leg.operatingBy) ??
          (id.carrier === "SU"
            ? (resolveCarrierByFlightNumber(id.flightNumber) ?? id.carrier)
            : id.carrier);
        const aircraft =
          leg.equipment?.aircraft?.actual?.title ??
          leg.equipment?.aircraft?.scheduled?.title ??
          null;
        const isLast = idx === legs.length - 1;
        const next = legs[idx + 1];
        const transferType =
          next && isConnecting ? "connecting" : next ? "multileg" : null;
        const transferKey =
          transferType === "connecting"
            ? "SHARED.FLIGHT-TRANSFER"
            : "SHARED.INTERMEDIATE-LANDING-PLURAL-ONE";
        // TZ §4.1.16.6 rule 12: show both stations if airport codes differ OR if the
        // IATA city codes differ (e.g. SVO→Moscow vs VKO→Moscow is same city, but
        // SVO→Moscow vs UFA→Ufa is different). Fall back to airport-code comparison
        // when cityCode is absent.
        const arrCityCode = leg.arrival.scheduled.cityCode;
        const depCityCode = next?.departure.scheduled.cityCode;
        const stationChange =
          next && (
            leg.arrival.scheduled.airportCode !== next.departure.scheduled.airportCode ||
            (arrCityCode && depCityCode && arrCityCode !== depCityCode)
          );
        // TZ §4.1.16.6 rule 14: if same airport but different terminals, show both.
        const arrTerminal = leg.arrival.terminal;
        const depTerminal = next?.departure.terminal;
        const terminalChange =
          next && !stationChange &&
          arrTerminal && depTerminal &&
          arrTerminal !== depTerminal;

        return (
          <div key={`leg-${idx}`}>
            <div className="schedule-flight-body__leg">
              <div className="schedule-flight-body__leg-number">{idx + 1}</div>
              <div className="schedule-flight-body__leg-flight-number">
                {`${id.carrier} ${id.flightNumber}${id.suffix ?? ""}`}
              </div>
              <div className="schedule-flight-body__leg-operator">
                <OperatorLogo carrier={carrier} locale={language} />
                {aircraft && (
                  <div className="schedule-flight-body__leg-aircraft">
                    {aircraft}
                  </div>
                )}
              </div>
              <div className="schedule-flight-body__leg-time">
                <TimeGroup
                  scheduled={leg.departure.times.scheduledDeparture.local}
                  dayChange={
                    leg.departure.times.scheduledDeparture.dayChange?.value
                  }
                />
              </div>
              <div className="schedule-flight-body__leg-station">
                <StationDisplay
                  airportCode={leg.departure.scheduled.airportCode}
                  airportName={leg.departure.scheduled.airport}
                  cityName={leg.departure.scheduled.city}
                  {...(leg.departure.terminal
                    ? { terminal: leg.departure.terminal }
                    : {})}
                  cityFirst
                />
              </div>
              <div className="schedule-flight-body__leg-duration">
                <span>{formatDuration(leg.flyingTime, language)}</span>
              </div>
              <div className="schedule-flight-body__leg-time schedule-flight-body__leg-time--arrival">
                <TimeGroup
                  scheduled={leg.arrival.times.scheduledArrival.local}
                  dayChange={
                    leg.arrival.times.scheduledArrival.dayChange?.value
                  }
                />
              </div>
              <div className="schedule-flight-body__leg-station schedule-flight-body__leg-station--arrival">
                <StationDisplay
                  airportCode={leg.arrival.scheduled.airportCode}
                  airportName={leg.arrival.scheduled.airport}
                  cityName={leg.arrival.scheduled.city}
                  {...(leg.arrival.terminal
                    ? { terminal: leg.arrival.terminal }
                    : {})}
                  cityFirst
                />
              </div>
            </div>

            {!isLast && next && transferType && (
              <div
                className={`schedule-flight-body__transfer schedule-flight-body__transfer--${transferType}`}
                data-testid="flight-transfer"
              >
                <div className="schedule-flight-body__transfer-icon">
                  <svg aria-hidden="true">
                    <use
                      xlinkHref={`/assets/img/sprite.svg#${
                        transferType === "connecting"
                          ? "flight-transfer"
                          : "intermediate-landing"
                      }`}
                    />
                  </svg>
                </div>
                <div className="schedule-flight-body__transfer-content">
                  <div className="schedule-flight-body__transfer-caption">
                    {t(transferKey)}
                  </div>
                  <div className="schedule-flight-body__transfer-time">
                    <img
                      src="/assets/img/time-orange.svg"
                      alt=""
                      aria-hidden="true"
                    />
                    <span>{formatDuration(transferDuration(leg, next), language)}</span>
                  </div>
                  <div className="schedule-flight-body__transfer-stations">
                    {stationChange ? (
                      <>
                        <span>
                          {leg.arrival.scheduled.city}, {leg.arrival.scheduled.airport}
                          {arrTerminal ? ` - ${arrTerminal}` : ""}
                        </span>
                        <span aria-hidden="true">{"→"}</span>
                        <span>
                          {next.departure.scheduled.city}, {next.departure.scheduled.airport}
                          {depTerminal ? ` - ${depTerminal}` : ""}
                        </span>
                      </>
                    ) : terminalChange ? (
                      // TZ §4.1.16.6 rule 14: same airport, different terminals
                      <>
                        <span>
                          {leg.arrival.scheduled.city}, {leg.arrival.scheduled.airport}
                          {arrTerminal ? ` - ${arrTerminal}` : ""}
                        </span>
                        <span aria-hidden="true">{"→"}</span>
                        <span>
                          {next.departure.scheduled.airport}
                          {depTerminal ? ` - ${depTerminal}` : ""}
                        </span>
                      </>
                    ) : (
                      <span>
                        {leg.arrival.scheduled.city}, {leg.arrival.scheduled.airport}
                        {arrTerminal ? ` - ${arrTerminal}` : ""}
                      </span>
                    )}
                  </div>
                </div>
              </div>
            )}
          </div>
        );
      })}

      {/* Angular search-results expanded body renders
          `<flight-details-body-actions>` → `<flight-actions>` with all
          defaults (share+buy+register+status, no print). The schedule
          details page suppresses these (page-level summary owns them),
          so callers opt in via `showActions`. Buy/Status visibility is
          gated by `<FlightActions>` (TZ §4.1.14.4.4 / §4.1.14.4.5).
          The flight details button is rendered after the other actions,
          matching Angular's `flight-actions` component layout. */}
      {showActions && (
        <div
          className="schedule-flight-body__actions"
          data-testid="schedule-flight-body-actions"
        >
          <FlightActions
            flight={flight}
            locale={locale}
            showShare
            showBuy
            showRegister
            showStatus
          />
          {onFlightDetails && (
            <button
              type="button"
              className="schedule-flight-body__details-btn"
              data-testid="flight-details-button"
              onClick={(e) => {
                e.stopPropagation();
                onFlightDetails(flight);
              }}
            >
              {t("SHARED.FLIGHT-DETAILS")}
            </button>
          )}
        </div>
      )}
    </div>
  );
};
