// @vitest-environment jsdom
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, waitFor } from "@testing-library/react";
import { useAppSettings } from "./useAppSettings.js";
import type { AppSettingsResponse } from "@/shared/api/appSettings.js";

const mockGetAppSettings = vi.fn();

vi.mock("@/shared/api/appSettings.js", () => ({
  getAppSettings: (...args: unknown[]) => mockGetAppSettings(...args),
}));

vi.mock("@/shared/api/provider.js", () => ({
  useApiClient: () => ({ get: vi.fn() }),
}));

describe("useAppSettings", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("parses searchFrom/searchTo strings into numbers", async () => {
    const response: AppSettingsResponse = {
      uiOptions: {
        filter: {
          onlineboard: { searchFrom: "2d", searchTo: "14d" },
          schedule: { searchFrom: "30d", searchTo: "45d" },
        },
      },
    };
    mockGetAppSettings.mockResolvedValue(response);

    const { result } = renderHook(() => useAppSettings());

    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.onlineboardSearchFrom).toBe(2);
    expect(result.current.onlineboardSearchTo).toBe(14);
    expect(result.current.scheduleSearchFrom).toBe(30);
    expect(result.current.scheduleSearchTo).toBe(45);
    expect(result.current.error).toBeNull();
  });

  it("returns defaults when uiOptions.filter is missing", async () => {
    const response: AppSettingsResponse = {};
    mockGetAppSettings.mockResolvedValue(response);

    const { result } = renderHook(() => useAppSettings());

    await waitFor(() => expect(result.current.loading).toBe(false));
    // Defaults match Angular AppSettings (boardSearch 1/7, scheduleSearch 1/330).
    expect(result.current.onlineboardSearchFrom).toBe(1);
    expect(result.current.onlineboardSearchTo).toBe(7);
    expect(result.current.scheduleSearchFrom).toBe(1);
    expect(result.current.scheduleSearchTo).toBe(330);
  });

  it("returns defaults when a specific value does not match /\\d+d/", async () => {
    const response: AppSettingsResponse = {
      uiOptions: {
        filter: {
          onlineboard: { searchFrom: "blah", searchTo: "14d" },
          schedule: { searchFrom: "30d", searchTo: "30d" },
        },
      },
    };
    mockGetAppSettings.mockResolvedValue(response);

    const { result } = renderHook(() => useAppSettings());

    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.onlineboardSearchFrom).toBe(1); // default, blah doesn't parse
    expect(result.current.onlineboardSearchTo).toBe(14);
  });

  it("starts with loading=true and returns error on failure", async () => {
    const err = new Error("network");
    mockGetAppSettings.mockRejectedValue(err);

    const { result } = renderHook(() => useAppSettings());

    expect(result.current.loading).toBe(true);
    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.error).toBe(err);
    expect(result.current.onlineboardSearchFrom).toBe(1);
  });

  it("parses buttons config into hour numbers", async () => {
    const response: AppSettingsResponse = {
      uiOptions: {
        buttons: {
          flightStatus: { availableFrom: "24h" },
          buyTicket: { period: { min: "2h", max: "72h" } },
        },
      },
    };
    mockGetAppSettings.mockResolvedValue(response);

    const { result } = renderHook(() => useAppSettings());

    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.flightStatusAvailableFromHours).toBe(24);
    expect(result.current.buyTicketMinHours).toBe(2);
    expect(result.current.buyTicketMaxHours).toBe(72);
  });

  it("returns button-config defaults when fields are missing", async () => {
    mockGetAppSettings.mockResolvedValue({});

    const { result } = renderHook(() => useAppSettings());

    await waitFor(() => expect(result.current.loading).toBe(false));
    // Defaults match Angular (flightStatusAvailableFrom: 2h, buyPeriod.min: 2h, buyPeriod.max: 330d).
    expect(result.current.flightStatusAvailableFromHours).toBe(2);
    expect(result.current.buyTicketMinHours).toBe(2);
    expect(result.current.buyTicketMaxHours).toBe(330 * 24);
  });

  it("parses buyPeriod.max in days (Angular API returns '330d')", async () => {
    const response: AppSettingsResponse = {
      uiOptions: {
        buttons: {
          buyTicket: { period: { min: "2h", max: "330d" } },
        },
      },
    };
    mockGetAppSettings.mockResolvedValue(response);

    const { result } = renderHook(() => useAppSettings());
    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.buyTicketMinHours).toBe(2);
    expect(result.current.buyTicketMaxHours).toBe(330 * 24);
  });
});
