/**
 * @vitest-environment jsdom
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render } from "@testing-library/react";
import { FlightsMapFilter } from "./FlightsMapFilter.js";
import type { IFlightsMapFilterState } from "../types.js";

// Capture props passed to PrimeReact Calendar.
let lastCalendarProps: Record<string, unknown> | null = null;
vi.mock("primereact/calendar", () => ({
  Calendar: (props: Record<string, unknown>) => {
    lastCalendarProps = props;
    return <div data-testid="fm-date-input" />;
  },
}));

// Stub the composite CityAutocomplete so rendering is cheap.
vi.mock("@/ui/city-autocomplete/index.js", () => ({
  CityAutocomplete: (props: Record<string, unknown>) => (
    <input
      data-testid={`${(props["testIdPrefix"] as string) ?? "cac"}-input`}
      placeholder={props["placeholder"] as string}
    />
  ),
}));

vi.mock("@/shared/dictionaries/index.js", () => ({
  useDictionaries: () => ({ dictionaries: null, loading: false, error: null }),
  findCityByCoord: () => null,
}));

vi.mock("@modern-js/runtime/router", () => ({
  useParams: () => ({ lang: "ru" }),
}));

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

function filter(
  overrides: Partial<IFlightsMapFilterState> = {},
): IFlightsMapFilterState {
  return {
    connections: false,
    domestic: false,
    international: false,
    ...overrides,
  };
}

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

function addDays(base: Date, n: number): Date {
  const d = new Date(base);
  d.setDate(d.getDate() + n);
  d.setHours(0, 0, 0, 0);
  return d;
}

describe("FlightsMapFilter — Calendar wiring", () => {
  beforeEach(() => {
    lastCalendarProps = null;
  });

  it("passes minDate and maxDate to Calendar", () => {
    const onChange = vi.fn();
    render(<FlightsMapFilter value={filter()} onChange={onChange} />);

    const min = lastCalendarProps!["minDate"] as Date;
    const max = lastCalendarProps!["maxDate"] as Date;

    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const expectedMin = addDays(today, -1);
    const expectedMax = new Date(today);
    expectedMax.setMonth(expectedMax.getMonth() + 6);

    expect(min.getTime()).toBe(expectedMin.getTime());
    expect(max.getTime()).toBe(expectedMax.getTime());
  });

  it("disables every date when availableDays is empty", () => {
    const onChange = vi.fn();
    render(
      <FlightsMapFilter value={filter()} availableDays={[]} onChange={onChange} />,
    );

    const disabled = lastCalendarProps!["disabledDates"] as Date[];
    expect(disabled.length).toBeGreaterThan(180);
  });

  it("excludes available days from disabledDates", () => {
    const onChange = vi.fn();
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const plusTwo = addDays(today, 2);

    render(
      <FlightsMapFilter
        value={filter()}
        availableDays={[yyyymmdd(plusTwo)]}
        onChange={onChange}
      />,
    );

    const disabled = lastCalendarProps!["disabledDates"] as Date[];
    const contains = disabled.some((d) => {
      const x = new Date(d);
      x.setHours(0, 0, 0, 0);
      return x.getTime() === plusTwo.getTime();
    });
    expect(contains).toBe(false);
  });

  it("snaps a disabled value.date forward to the next available day", () => {
    const onChange = vi.fn();
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const plusOne = addDays(today, 1);
    const plusTwo = addDays(today, 2);

    render(
      <FlightsMapFilter
        value={filter({ date: yyyymmdd(plusOne) })}
        availableDays={[yyyymmdd(plusTwo)]}
        onChange={onChange}
      />,
    );

    expect(onChange).toHaveBeenCalled();
    const called = onChange.mock.calls[0]![0] as IFlightsMapFilterState;
    expect(called.date).toBe(yyyymmdd(plusTwo));
  });

  it("clears value.date when no enabled date exists in the window", () => {
    const onChange = vi.fn();
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const plusOne = addDays(today, 1);

    render(
      <FlightsMapFilter
        value={filter({ date: yyyymmdd(plusOne) })}
        availableDays={[]}
        onChange={onChange}
      />,
    );

    expect(onChange).toHaveBeenCalled();
    const called = onChange.mock.calls[0]![0] as IFlightsMapFilterState;
    expect(called.date).toBeUndefined();
  });

  it("does not snap when the current date is already enabled", () => {
    const onChange = vi.fn();
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const plusTwo = addDays(today, 2);

    render(
      <FlightsMapFilter
        value={filter({ date: yyyymmdd(plusTwo) })}
        availableDays={[yyyymmdd(plusTwo)]}
        onChange={onChange}
      />,
    );

    expect(onChange).not.toHaveBeenCalled();
  });
});
