import { useState, type FC, type KeyboardEvent, type ReactNode } from "react";
import { useTranslation } from "@/i18n/provider.js";
import { useLocale } from "@/i18n/useLocale.js";
import type { ISimpleFlight, IFlightLeg } from "@/features/online-board/types.js";
import { operatingCarrier } from "@/features/online-board/types.js";
import { resolveCarrierByFlightNumber } from "@/shared/operatorIcon.js";
import {
  formatLocalTime,
  formatUtcOffset,
} from "@/shared/utils/datetime/index.js";
import {
  dayChangeBadgeTooltip,
  formatDayChangeBadge,
} from "@/features/online-board/dayChange.js";
import { StationDisplay } from "./StationDisplay.js";
import { TimeGroup } from "./TimeGroup.js";
import { FlightStatus } from "./FlightStatus.js";
import { OperatorLogo } from "./OperatorLogo.js";
import { IFlyWarning } from "./IFlyWarning.js";
import { FlightEvents } from "@/features/online-board/components/BoardDetailsHeader/FlightEvents.js";
import "./FlightCard.scss";

export interface FlightCardProps {
  flight: ISimpleFlight;
  /**
   * Legacy single-click navigation handler. Kept for callers that don't
   * need inline expansion (e.g. details-page summary row).
   */
  onClick?: () => void;
  /**
   * When true, a single row click toggles an inline detail panel (time
   * row, boarding row, 'Детали рейса' button) and the bottom button
   * fires onViewDetails. Matches Angular's board-flight-header behaviour.
   */
  expandable?: boolean;
  /**
   * Opens the inline panel on mount — used by the 'closest flight'
   * auto-selection Angular ships on search results.
   */
  initialExpanded?: boolean;
  /** Fired when the user clicks 'Детали рейса' in the expanded panel. */
  onViewDetails?: () => void;
  /**
   * Search direction. `arrival` swaps the boarding row to deboarding
   * (label `Высадка` instead of `Посадка`). Aircraft model is only shown
   * in the expanded body for direct flights (matches Angular's
   * `[showModel]="expanded && direct"` on operator-logo-and-model).
   */
  direction?: "departure" | "arrival" | "route" | "flight" | "schedule";
  /**
   * Optional render override for the expanded body. When provided,
   * replaces the default time/transition rows — used by schedule
   * pages to render the per-leg route diagram.
   */
  renderExpandedBody?: (flight: ISimpleFlight) => ReactNode;
  /**
   * Extra action buttons rendered before the default share + details
   * buttons in the expanded actions row. Used by the online-board
   * search page to surface the same Купить / Онлайн регистрация
   * buttons Angular shows on the search results expansion.
   */
  renderActions?: (flight: ISimpleFlight) => ReactNode;
  /**
   * Aeroflot booking URL for the per-row "Купить билет" hover link
   * (TIRREDESIGN-6 / TZ §4.1.14.4.4). Rendered inside the collapsed row
   * only on Schedule layouts; absent in the row flow on other directions.
   * CSS shows the link on hover on desktop and hides it entirely on
   * mobile / tablet.
   */
  inlineBuyUrl?: string;
}

/** Extract the primary leg from a flight (first leg for multi-leg) */
function getPrimaryLeg(flight: ISimpleFlight): IFlightLeg {
  if (flight.routeType === "Direct") return flight.leg;
  const first = flight.legs[0];
  if (!first) throw new Error("Multi-leg flight has no legs");
  return first;
}

/** Extract the final leg (last leg for multi-leg, same as primary for direct) */
function getFinalLeg(flight: ISimpleFlight): IFlightLeg {
  if (flight.routeType === "Direct") return flight.leg;
  const last = flight.legs[flight.legs.length - 1];
  if (!last) throw new Error("Multi-leg flight has no legs");
  return last;
}

/** Pretty "HH:mm UTC±HH:mm" string from an offset-aware ISO timestamp. */
function timeWithOffset(iso: string | undefined): string {
  if (!iso) return "";
  const time = formatLocalTime(iso);
  const offset = formatUtcOffset(iso);
  return offset ? `${time} ${offset}` : time;
}

/**
 * Convert API flyingTime ("HH:MM:SS" or ISO-8601 "PT1H30M") to the
 * locale-formatted Angular `DurationPipe` output ("1ч. 30мин." for ru).
 */
function formatFlyingTime(value: string, 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;
    }
  }
  if (isRu) return `${h}ч. ${m}мин.`;
  return `${h}h ${m}m`;
}

function formatMinutes(total: number, language: string): string {
  if (!Number.isFinite(total) || total < 0) return "";
  const isRu = language.startsWith("ru");
  const h = Math.floor(total / 60);
  const m = total % 60;
  if (isRu) return `${h}ч. ${m}мин.`;
  return `${h}h ${m}m`;
}

function totalElapsedMinutes(flight: ISimpleFlight): number | null {
  const legs = flight.routeType === "Direct" ? [flight.leg] : flight.legs;
  const first = legs[0];
  const last = legs[legs.length - 1];
  if (!first || !last) return null;
  const depUtc = first.departure.times.scheduledDeparture.utc;
  const arrUtc = last.arrival.times.scheduledArrival.utc;
  if (!depUtc || !arrUtc) return null;
  const diffMs = Date.parse(arrUtc) - Date.parse(depUtc);
  if (!Number.isFinite(diffMs) || diffMs <= 0) return null;
  return Math.round(diffMs / 60000);
}

/**
 * A single flight row in search results.
 *
 * Header row matches Angular's board-flight-header layout:
 * flight#+aircraft | operator-logo | dep-time | dep-city/terminal | status-icon | arr-time | arr-city/terminal | chevron
 *
 * When `expandable`, a row click toggles an inline details panel with
 * scheduled/expected time rows for departure + arrival, a boarding
 * status row, and a 'Детали рейса' navigation button.
 */
export const FlightCard: FC<FlightCardProps> = ({
  flight,
  onClick,
  expandable,
  initialExpanded,
  onViewDetails,
  direction = "route",
  renderExpandedBody,
  renderActions,
  inlineBuyUrl,
}) => {
  const { t } = useTranslation();
  const { language } = useLocale();
  const departureLeg = getPrimaryLeg(flight);
  const arrivalLeg = getFinalLeg(flight);

  const depStation = departureLeg.departure;
  const arrStation = arrivalLeg.arrival;
  const depTimes = depStation.times;
  const arrTimes = arrStation.times;

  // Connecting flights get folded into a synthetic MultiLeg shape with
  // an extra `_childFlightIds` array so we can render `SU 6188, SU 6233`
  // — Angular's `schedule-list-flight-header` does the same via
  // `flightNumber` pipe over `getFlights()`.
  const childFlightIds = (flight as ISimpleFlight & {
    _childFlightIds?: { carrier: string; flightNumber: string; suffix?: string }[];
  })._childFlightIds;
  const flightNumber = childFlightIds && childFlightIds.length > 1
    ? childFlightIds
        .map((id) => `${id.carrier} ${id.flightNumber}${id.suffix ?? ""}`)
        .join(", ")
    : `${flight.flightId.carrier} ${flight.flightId.flightNumber}`;
  // TZ §4.1.22: when OperatingBy is null, resolve carrier from flight-number
  // ranges (SU1-2999→SU, SU5000-5399→DP, SU5400-5799→HZ, etc.).
  // Falls back to the flight's own carrier code for non-SU flights or when
  // range resolution returns null (ranges with no icon).
  const carrier =
    operatingCarrier(flight.operatingBy) ??
    (flight.flightId.carrier === "SU"
      ? (resolveCarrierByFlightNumber(flight.flightId.flightNumber) ?? flight.flightId.carrier)
      : flight.flightId.carrier);
  const isMultiLeg = flight.routeType === "MultiLeg";
  const aircraftName =
    departureLeg.equipment?.aircraft?.actual?.title ??
    departureLeg.equipment?.aircraft?.scheduled?.title ??
    null;

  // Total duration shown in the middle column on schedule rows. Prefer
  // the flight-level flyingTime; fall back to the primary leg.
  const flightDuration = flight.flyingTime || departureLeg.flyingTime || "";

  // Flags: route-changed / return-to-airport per TZ §4.1.13.3 Table 24 C15–C16.
  // Must be visible in the collapsed row for both direct and multi-leg flights.
  const allLegs = flight.routeType === "Direct" ? [flight.leg] : flight.legs;
  const routeChanged = allLegs.some((l) => l.flags.routeChanged);
  const returnToAirport = allLegs.some((l) => l.flags.returnToAirport);

  const [expanded, setExpanded] = useState(Boolean(initialExpanded));
  const rowClickable = expandable || Boolean(onClick);
  const toggleExpanded = (): void => {
    if (expandable) {
      setExpanded((v) => !v);
    } else if (onClick) {
      onClick();
    }
  };

  const depScheduled = timeWithOffset(depTimes.scheduledDeparture.local);
  // Angular shows the latest available dep time as actual>estimated.
  // The caption changes with it: 'Фактическое' for actual, 'Ожидаемое'
  // for estimated-only.
  const depLatestTimes = depTimes.actualBlockOff ?? depTimes.estimatedBlockOff;
  const depLatest = depLatestTimes ? timeWithOffset(depLatestTimes.local) : null;
  const depLatestCaptionKey = depTimes.actualBlockOff
    ? "SHARED.ACTUAL"
    : "SHARED.EXPECTED";
  const arrScheduled = timeWithOffset(arrTimes.scheduledArrival.local);
  const arrLatestTimes = arrTimes.actualBlockOn ?? arrTimes.estimatedBlockOn;
  const arrLatest = arrLatestTimes ? timeWithOffset(arrLatestTimes.local) : null;
  const arrLatestCaptionKey = arrTimes.actualBlockOn
    ? "SHARED.ACTUAL"
    : "SHARED.EXPECTED";

  // TIRREDESIGN-7 / TZ §4.1.13.4.1-3: the inline expanded panel renders
  // registration (check-in), boarding and deboarding rows side-by-side,
  // each visible independently when its `isActual` flag is true. Matches
  // Angular's `board-flight-body` template which ngIfs on
  // `transition?.X?.isActual` for all three blocks. `direction` no
  // longer gates which single block wins — gate/dispatch/bag-belt
  // still come from the appropriate end of the leg though.
  const registration = departureLeg.transition?.registration;
  const boarding = departureLeg.transition?.boarding;
  const deboarding = arrivalLeg.transition?.deboarding;
  const showRegistration = Boolean(registration?.isActual);
  const showBoarding = Boolean(boarding?.isActual);
  const showDeboarding = Boolean(deboarding?.isActual);
  const anyTransition = showRegistration || showBoarding || showDeboarding;

  const BOARDING_STATUS_KEY: Record<string, string> = {
    Finished: "BOARDING-STATUSES.Finished",
    Expected: "BOARDING-STATUSES.Expected",
    InProgress: "BOARDING-STATUSES.InProgress",
    Specified: "BOARDING-STATUSES.Specified",
    Scheduled: "BOARDING-STATUSES.Scheduled",
  };

  const renderTransitionRow = (
    key: "registration" | "boarding" | "deboarding",
    item: NonNullable<typeof boarding>,
  ): JSX.Element => {
    const labelKey =
      key === "registration"
        ? "DETAILS.REGISTRATION"
        : key === "boarding"
          ? "DETAILS.BOARDING"
          : "DETAILS.DEBOARDING";
    // "Время начала" / "Время окончания" apply to all three rows —
    // Angular reuses the same SHARED.BOARDING-START/END strings for
    // registration rows too.
    const startKey = "SHARED.BOARDING-START";
    const endKey = "SHARED.BOARDING-END";
    // Gate + dispatch surface on boarding (departure side); gate + bag
    // belt surface on deboarding (arrival side). Registration has no
    // gate-like affordance in the API payload.
    const gate = key === "boarding" ? depStation.gate : key === "deboarding" ? arrStation.gate : undefined;
    const dispatch = key === "boarding" ? depStation.dispatch : undefined;
    const bagBelt = key === "deboarding" ? arrStation.bagBelt : undefined;
    return (
      <div className="flight-card__detail-row" key={key} data-transition={key}>
        <div className="flight-card__detail-label">{t(labelKey)}</div>
        <div className="flight-card__detail-group">
          <div>
            <span className="flight-card__detail-caption">{t("DETAILS.STATUS")}</span>
            <span
              className={`flight-card__detail-value flight-card__detail-status flight-card__detail-status--${item.status.toLowerCase()}`}
            >
              <span className="flight-card__status-dot" aria-hidden="true" />
              {t(BOARDING_STATUS_KEY[item.status] ?? item.status)}
            </span>
          </div>
          {item.start?.local && (
            <div>
              <span className="flight-card__detail-caption">{t(startKey)}</span>
              <span className="flight-card__detail-value">
                {formatLocalTime(item.start.local)}
              </span>
            </div>
          )}
          {item.end?.local && (
            <div>
              <span className="flight-card__detail-caption">{t(endKey)}</span>
              <span className="flight-card__detail-value">
                {formatLocalTime(item.end.local)}
              </span>
            </div>
          )}
          {gate && (
            <div data-testid="transition-gate">
              <span className="flight-card__detail-caption">{t("DETAILS.GATE")}</span>
              <span className="flight-card__detail-value">{gate}</span>
            </div>
          )}
          {dispatch && (
            <div data-testid="transition-dispatch">
              <span className="flight-card__detail-caption">{t("DETAILS.DISPATCH")}</span>
              <span className="flight-card__detail-value">{t(`DISPATCH.${dispatch}`)}</span>
            </div>
          )}
          {bagBelt && (
            <div data-testid="transition-bag-belt">
              <span className="flight-card__detail-caption">{t("DETAILS.BAG_BELT")}</span>
              <span className="flight-card__detail-value">{bagBelt}</span>
            </div>
          )}
        </div>
      </div>
    );
  };

  return (
    <div
      className={`flight-card${direction === "schedule" ? " flight-card--schedule" : ""}${rowClickable ? " flight-card--clickable" : ""}${expanded ? " flight-card--expanded" : ""}`}
      data-flight-id={flight.id}
    >
      <div
        className="flight-card__row"
        {...(rowClickable
          ? {
              role: "button",
              tabIndex: 0,
              ...(expandable ? { "aria-expanded": expanded } : {}),
              onClick: toggleExpanded,
              onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  toggleExpanded();
                }
              },
            }
          : {})}
      >
        <div className="flight-card__number" data-testid="flight-carrier-number">
          {/* Angular's `schedule-list-flight-header` stacks each leg's
              flight number on its own line (e.g. "SU 6951," / "SU 6345")
              in the schedule row. Outside schedule mode we keep the
              existing single-line presentation. */}
          {direction === "schedule" && childFlightIds && childFlightIds.length > 1 ? (
            childFlightIds.map((id, i) => (
              <div key={`${id.carrier}-${id.flightNumber}-${i}`}>
                {id.carrier} {id.flightNumber}{id.suffix ?? ""}{i < childFlightIds.length - 1 ? "," : ""}
              </div>
            ))
          ) : (
            <div>{flightNumber}</div>
          )}
          {expanded && flight.routeType === "Direct" && aircraftName && (
            <div className="flight-card__aircraft">{aircraftName}</div>
          )}
          {/* TZ §4.1.13.3 Table 24 C15–C16: route-changed / return-to-airport
              icons are shown in the collapsed row for any flight with those flags.
              showDescription=false keeps the icon-only compact variant. */}
          {(routeChanged || returnToAirport) && (
            <FlightEvents
              changeRoute={routeChanged}
              reroute={returnToAirport}
              showDescription={false}
            />
          )}
        </div>

        <div className="flight-card__operator">
          {isMultiLeg
            ? flight.legs.map((leg, i) => (
                <OperatorLogo
                  key={`${operatingCarrier(leg.operatingBy) ?? carrier}-${i}`}
                  carrier={operatingCarrier(leg.operatingBy) ?? carrier}
                  locale={language}
                  // Multi-leg schedule rows always use the small round
                  // airline badges in the header — expanding the row
                  // must not swap them for the wide rectangular logo
                  // that overflows the operator column.
                  round={direction === "schedule"}
                />
              ))
            : <OperatorLogo carrier={carrier} locale={language} />}
        </div>

        <div className="flight-card__time">
          {/* TZ §4.1.17-R4: each time type gets its own independent badge */}
          <TimeGroup
            scheduled={depTimes.scheduledDeparture.local}
            actual={depTimes.actualBlockOff?.local}
            scheduledDayChange={depTimes.scheduledDeparture.dayChange?.value}
            actualDayChange={
              depTimes.actualBlockOff?.dayChange.value ??
              depTimes.estimatedBlockOff?.dayChange.value
            }
          />
        </div>

        <div className="flight-card__station">
          <StationDisplay
            airportCode={depStation.scheduled.airportCode}
            airportName={depStation.scheduled.airport}
            cityName={depStation.scheduled.city}
            {...(depStation.terminal ? { terminal: depStation.terminal } : {})}
            cityFirst
          />
        </div>

        {direction === "schedule" ? (
          <div className="flight-card__duration" data-testid="flight-duration">
            <span className="flight-card__duration-icon" aria-hidden="true" />
            <span className="flight-card__duration-text">
              {flight.routeType === "MultiLeg"
                ? (() => {
                    // TZ §4.1.14.3: total duration = segments + pauses.
                    // API's flyingTime is air-time only; use last-arrival minus
                    // first-departure elapsed time so connecting trips match Angular.
                    const mins = totalElapsedMinutes(flight);
                    return mins != null
                      ? formatMinutes(mins, language)
                      : formatFlyingTime(flightDuration, language);
                  })()
                : formatFlyingTime(flightDuration, language)}
            </span>
          </div>
        ) : (
          <div className="flight-card__status">
            <FlightStatus status={flight.status} />
          </div>
        )}

        <div className="flight-card__time flight-card__time--arrival">
          {/* TZ §4.1.17-R4: each time type gets its own independent badge */}
          <TimeGroup
            scheduled={arrTimes.scheduledArrival.local}
            actual={arrTimes.actualBlockOn?.local}
            scheduledDayChange={arrTimes.scheduledArrival.dayChange?.value}
            actualDayChange={
              arrTimes.actualBlockOn?.dayChange.value ??
              arrTimes.estimatedBlockOn?.dayChange.value
            }
          />
        </div>

        <div className="flight-card__station flight-card__station--arrival">
          <StationDisplay
            airportCode={arrStation.scheduled.airportCode}
            airportName={arrStation.scheduled.airport}
            cityName={arrStation.scheduled.city}
            {...(arrStation.terminal ? { terminal: arrStation.terminal } : {})}
            cityFirst
          />
        </div>

        {inlineBuyUrl && (
          <a
            href={inlineBuyUrl}
            target="_blank"
            rel="noopener noreferrer"
            className="flight-card__buy-link"
            data-testid="flight-card-buy-link"
            onClick={(e) => e.stopPropagation()}
          >
            {t("SHARED.BUY-TICKET")}
          </a>
        )}

        {(expandable || direction === "schedule") && (
          <div
            className={`flight-card__chevron${expanded ? " flight-card__chevron--open" : ""}`}
            aria-hidden="true"
          >
            {"\u25BE"}
          </div>
        )}
      </div>

      {/* Angular `schedule-list-flight-header` renders a compact transfer
          bar below the row when the flight is collapsed and connecting
          (`*ngIf="!flight.expanded && flight.boardings >= 1"`). */}
      {direction === "schedule" && !expanded && flight.routeType !== "Direct" &&
        flight.legs.length > 1 && (
          <div
            className="flight-card__transfer"
            data-testid="flight-card-transfer"
          >
            <span className="flight-card__transfer-icon" aria-hidden="true">
              <svg viewBox="0 0 20 8" width="20" height="8">
                <circle cx="3" cy="4" r="3" fill="currentColor" />
                <path d="M6 4h8" stroke="currentColor" strokeWidth="1.5" />
                <circle cx="17" cy="4" r="3" fill="currentColor" />
              </svg>
            </span>
            <span className="flight-card__transfer-label">
              {t(
                flight.legs.length > 2
                  ? "SHARED.INTERMEDIATE-LANDING-PLURAL-OTHER"
                  : "SHARED.FLIGHT-TRANSFER-PLURAL-ONE",
              )}
            </span>
            <span className="flight-card__transfer-dash">&nbsp;&mdash;&nbsp;</span>
            <span className="flight-card__transfer-stations">
              {flight.legs.slice(0, -1).map((l, i) => {
                const s = l.arrival.scheduled;
                const terminal = l.arrival.terminal;
                const airportWithTerminal = terminal
                  ? `${s.airport} - ${terminal}`
                  : s.airport;
                return (
                  <span key={`tr-${i}`}>
                    {i > 0 ? ", " : ""}
                    {s.city}
                    {s.airport ? (
                      <>
                        {", "}
                        <span className="flight-card__transfer-airport">
                          {airportWithTerminal}
                        </span>
                      </>
                    ) : null}
                  </span>
                );
              })}
            </span>
          </div>
        )}

      {expandable && expanded && renderExpandedBody && (
        <div
          className="flight-card__expanded flight-card__expanded--custom"
          data-testid="flight-card-expanded"
        >
          <IFlyWarning
            flightNumber={flight.flightId.flightNumber}
            variant="small"
          />
          {renderExpandedBody(flight)}
        </div>
      )}

      {expandable && expanded && !renderExpandedBody && (
        <div className="flight-card__expanded" data-testid="flight-card-expanded">
          <IFlyWarning
            flightNumber={flight.flightId.flightNumber}
            variant="small"
          />
          {/* TZ §4.1.17-R7: day-change badges in expanded row (per-time-type) */}
          <div className="flight-card__detail-row">
            <div className="flight-card__detail-label">{t("SHARED.TIME")}</div>
            <div className="flight-card__detail-group">
              <div>
                <span className="flight-card__detail-caption">
                  {t("SHARED.SCHEDULED")}
                </span>
                <span className="flight-card__detail-value">{depScheduled}</span>
                {(() => {
                  const dc = depTimes.scheduledDeparture.dayChange?.value ?? 0;
                  const badge = formatDayChangeBadge(dc);
                  return badge ? (
                    <span
                      className="time-group__day-change"
                      title={dayChangeBadgeTooltip(
                        depTimes.scheduledDeparture.local,
                        dc,
                      )}
                    >
                      {badge}
                    </span>
                  ) : null;
                })()}
              </div>
              {depLatest && (
                <div>
                  <span className="flight-card__detail-caption">
                    {t(depLatestCaptionKey)}
                  </span>
                  <span className="flight-card__detail-value">{depLatest}</span>
                  {(() => {
                    const dc =
                      depLatestTimes?.dayChange?.value ?? 0;
                    const badge = formatDayChangeBadge(dc);
                    return badge && depLatestTimes ? (
                      <span
                        className="time-group__day-change"
                        title={dayChangeBadgeTooltip(depLatestTimes.local, dc)}
                      >
                        {badge}
                      </span>
                    ) : null;
                  })()}
                </div>
              )}
            </div>
            <div className="flight-card__detail-group">
              <div>
                <span className="flight-card__detail-caption">
                  {t("SHARED.SCHEDULED")}
                </span>
                <span className="flight-card__detail-value">{arrScheduled}</span>
                {(() => {
                  const dc = arrTimes.scheduledArrival.dayChange?.value ?? 0;
                  const badge = formatDayChangeBadge(dc);
                  return badge ? (
                    <span
                      className="time-group__day-change"
                      title={dayChangeBadgeTooltip(
                        arrTimes.scheduledArrival.local,
                        dc,
                      )}
                    >
                      {badge}
                    </span>
                  ) : null;
                })()}
              </div>
              {arrLatest && (
                <div>
                  <span className="flight-card__detail-caption">
                    {t(arrLatestCaptionKey)}
                  </span>
                  <span className="flight-card__detail-value">{arrLatest}</span>
                  {(() => {
                    const dc =
                      arrLatestTimes?.dayChange?.value ?? 0;
                    const badge = formatDayChangeBadge(dc);
                    return badge && arrLatestTimes ? (
                      <span
                        className="time-group__day-change"
                        title={dayChangeBadgeTooltip(arrLatestTimes.local, dc)}
                      >
                        {badge}
                      </span>
                    ) : null;
                  })()}
                </div>
              )}
            </div>
          </div>

          {anyTransition && (
            <>
              {showRegistration && registration && renderTransitionRow("registration", registration)}
              {showBoarding && boarding && renderTransitionRow("boarding", boarding)}
              {showDeboarding && deboarding && renderTransitionRow("deboarding", deboarding)}
            </>
          )}

          {onViewDetails && (
            <div className="flight-card__actions">
              <button
                type="button"
                className="flight-card__share-btn"
                data-testid="flight-share-button"
                aria-label={t("BOARD.SHARE")}
                title={t("BOARD.SHARE")}
                onClick={(e) => {
                  e.stopPropagation();
                  const url = typeof window !== "undefined"
                    ? window.location.href
                    : "";
                  const navShare = (
                    typeof navigator !== "undefined" &&
                      (navigator as Navigator & { share?: (data: ShareData) => Promise<void> }).share
                  );
                  if (navShare && url) {
                    void navShare.call(navigator, { url });
                  } else if (url && typeof navigator !== "undefined" && navigator.clipboard) {
                    void navigator.clipboard.writeText(url);
                  }
                }}
              >
                <img src="/assets/img/share.svg" alt="" aria-hidden="true" />
              </button>
              {/* Extra actions (Купить / Онлайн регистрация). Angular
                  renders Buy + Registration + Details here on every
                  expanded board row; the caller wires up FlightActions
                  via renderActions so the visibility rules live with
                  the feature instead of leaking into the ui layer. */}
              {renderActions?.(flight)}
              <button
                type="button"
                className="flight-card__details-btn"
                data-testid="flight-details-button"
                onClick={(e) => {
                  e.stopPropagation();
                  onViewDetails();
                }}
              >
                {t("BOARD.DETAILS-TITLE")}
              </button>
            </div>
          )}
        </div>
      )}
    </div>
  );
};
