// @vitest-environment jsdom
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import type { IFlightLeg, IDuration } from "../../types.js";

vi.mock("@/i18n/provider.js", () => ({
  useTranslation: () => ({ t: (k: string) => k }),
}));

import { Timeline } from "./Timeline.js";

function makeLeg(
  i: number,
  overrides: {
    actualDepLocal?: string;
    actualArrLocal?: string;
    estimatedDuration?: IDuration;
    /** day-change value on scheduledArrival */
    scheduledArrDayChange?: number;
    /** day-change value on scheduledDeparture */
    scheduledDepDayChange?: number;
    /** day-change value on actualBlockOn */
    actualArrDayChange?: number;
    /** day-change value on actualBlockOff */
    actualDepDayChange?: number;
  } = {},
): IFlightLeg {
  return {
    arrival: {
      scheduled: {
        airport: "",
        airportCode: "AAA",
        city: `City${i}`,
        cityCode: `C${i}`,
        countryCode: "RU",
      },
      terminal: "",
      times: {
        scheduledArrival: {
          dayChange: { value: overrides.scheduledArrDayChange ?? 0, title: "" },
          local: `a${i}`,
          localTime: `a${i}`,
          tzOffset: 0,
          utc: `2026-04-17T0${i}:00:00Z`,
        },
        actualBlockOn: overrides.actualArrLocal
          ? {
              dayChange: { value: overrides.actualArrDayChange ?? 0, title: "" },
              local: overrides.actualArrLocal,
              localTime: overrides.actualArrLocal,
              tzOffset: 0,
              utc: `2026-04-17T0${i}:00:00Z`,
            }
          : undefined,
      },
    },
    departure: {
      scheduled: {
        airport: "",
        airportCode: "BBB",
        city: `Dep${i}`,
        cityCode: `D${i}`,
        countryCode: "RU",
      },
      terminal: "",
      checkingStatus: "",
      times: {
        scheduledDeparture: {
          dayChange: { value: overrides.scheduledDepDayChange ?? 0, title: "" },
          local: `d${i}`,
          localTime: `d${i}`,
          tzOffset: 0,
          utc: `2026-04-17T0${i}:00:00Z`,
        },
        actualBlockOff: overrides.actualDepLocal
          ? {
              dayChange: { value: overrides.actualDepDayChange ?? 0, title: "" },
              local: overrides.actualDepLocal,
              localTime: overrides.actualDepLocal,
              tzOffset: 0,
              utc: `2026-04-17T0${i}:00:00Z`,
            }
          : undefined,
      },
    },
    dayChange: 0,
    equipment: {},
    flags: { checkinAvailable: false, returnToAirport: false, routeChanged: false },
    flyingTime: `${i}h`,
    index: i,
    operatingBy: {},
    status: "Scheduled",
    updated: "",
    estimatedDuration: overrides.estimatedDuration,
  } as IFlightLeg;
}

describe("Timeline", () => {
  it("renders times for 2 legs at index 0", () => {
    const legs = [makeLeg(0), makeLeg(1)];
    render(<Timeline legs={legs} canChange={false} />);
    expect(screen.getByText("d0")).toBeTruthy();
    expect(screen.getByText("a0")).toBeTruthy();
    expect(screen.getByText("d1")).toBeTruthy();
    expect(screen.getByText("a1")).toBeTruthy();
  });

  it("does not render prev arrow on first page", () => {
    const legs = [makeLeg(0), makeLeg(1)];
    render(<Timeline legs={legs} canChange={false} />);
    expect(screen.queryByTestId("timeline-prev")).toBeNull();
  });

  it("does not render next arrow on last pair (2 legs)", () => {
    const legs = [makeLeg(0), makeLeg(1)];
    render(<Timeline legs={legs} canChange={false} />);
    expect(screen.queryByTestId("timeline-next")).toBeNull();
  });

  it("shows next arrow with 3 legs, clicking advances", () => {
    const legs = [makeLeg(0), makeLeg(1), makeLeg(2)];
    render(<Timeline legs={legs} canChange={false} />);
    const nextBtn = screen.getByTestId("timeline-next");
    expect(nextBtn).toBeTruthy();
    fireEvent.click(nextBtn);
    expect(screen.getByText("d2")).toBeTruthy();
    expect(screen.queryByText("d0")).toBeNull();
  });

  it("applies specifying class when canChange=true and estimatedDuration.isNegative", () => {
    const legs = [
      makeLeg(0, { estimatedDuration: { days: 0, hours: 1, minutes: 0, isNegative: true } }),
      makeLeg(1),
    ];
    const { container } = render(<Timeline legs={legs} canChange={true} />);
    expect(container.querySelector(".timeline-section__duration--specifying")).not.toBeNull();
  });

  it("prefers latest times when canChange=true (falls back to scheduled when no actual)", () => {
    const legs = [
      makeLeg(0, { actualDepLocal: "dx0", actualArrLocal: "ax0" }),
      makeLeg(1), // no actual, falls back
    ];
    render(<Timeline legs={legs} canChange={true} />);
    expect(screen.getByText("dx0")).toBeTruthy();
    expect(screen.getByText("ax0")).toBeTruthy();
    // leg 1 has no actuals — falls back to scheduled
    expect(screen.getByText("d1")).toBeTruthy();
    expect(screen.getByText("a1")).toBeTruthy();
  });

  describe("§4.1.15.5 Маршрут day-change badges (+X/-X)", () => {
    it("4.1.15.5-DC-None: does not render day-change badge when value is 0", () => {
      const legs = [
        makeLeg(0, { scheduledArrDayChange: 0 }),
        makeLeg(1, { scheduledDepDayChange: 0 }),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      expect(screen.queryByTestId("timeline-day-change")).toBeNull();
    });

    it("4.1.15.5-DC-ScheduledArr+1: renders +1 badge on arrival time when scheduledArrival.dayChange=+1", () => {
      const legs = [
        makeLeg(0, { scheduledArrDayChange: 1 }),
        makeLeg(1),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("+1");
    });

    it("4.1.15.5-DC-ScheduledArr+2: renders +2 badge when dayChange value is 2", () => {
      const legs = [
        makeLeg(0, { scheduledArrDayChange: 2 }),
        makeLeg(1),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("+2");
    });

    it("4.1.15.5-DC-ScheduledArr-1: renders -1 badge when dayChange value is -1", () => {
      const legs = [
        makeLeg(0, { scheduledArrDayChange: -1 }),
        makeLeg(1),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("-1");
    });

    it("4.1.15.5-DC-PreferActual: uses actualBlockOn dayChange when canChange=true and actual present", () => {
      const legs = [
        // scheduledArrDayChange=0, but actual has +1 — badge should show +1
        makeLeg(0, {
          actualArrLocal: "ax0",
          actualArrDayChange: 1,
          scheduledArrDayChange: 0,
        }),
        makeLeg(1),
      ];
      render(<Timeline legs={legs} canChange={true} />);
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("+1");
    });

    it("4.1.15.5-DC-FallbackScheduled: falls back to scheduled dayChange when canChange=true but no actual", () => {
      const legs = [
        makeLeg(0, { scheduledArrDayChange: 1 }),
        makeLeg(1),
      ];
      render(<Timeline legs={legs} canChange={true} />);
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("+1");
    });

    it("4.1.15.5-DC-DepBadge: renders day-change badge on departure time (not just arrival)", () => {
      const legs = [
        makeLeg(0),
        // departure of leg 1 has +1 day change (flights that depart next day)
        makeLeg(1, { scheduledDepDayChange: 1 }),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      // At least one badge should be present
      expect(screen.getByTestId("timeline-day-change").textContent).toBe("+1");
    });

    it("4.1.15.5-DC-MultipleBadges: renders multiple badges when several times cross midnight", () => {
      const legs = [
        // Leg 0 arrives +1; leg 1 departs +1 and arrives +2
        makeLeg(0, { scheduledArrDayChange: 1 }),
        makeLeg(1, { scheduledDepDayChange: 1, scheduledArrDayChange: 2 }),
      ];
      render(<Timeline legs={legs} canChange={false} />);
      const badges = screen.getAllByTestId("timeline-day-change");
      // We render dep0, arr0, dep1, arr1 — three of them have non-zero day-change
      expect(badges.length).toBe(3);
    });
  });
});
