import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { TRPCError } from "@trpc/server";
import { injectable } from "inversify";
import { navigationContainer } from "@/di/container";
import { NavigationModule } from "@/di/module";
import { NAVIGATION_SYMBOLS } from "@/di/symbols";
import { getHeaderUseCase } from "@/application/use-cases/get-header.use-case";
import { getHeaderController } from "@/interface-adapters/controllers/get-header.controller";
import { navigationRouter } from "@/integrations/api/router";

describe("navigationRouter", () => {
  beforeEach(() => {
    navigationContainer.unbindAll();
    navigationContainer.load(NavigationModule);
  });

  afterEach(() => {
    navigationContainer.unbindAll();
  });

  it("exposes header procedure", () => {
    const names = Object.keys(navigationRouter._def.procedures);
    expect(names).toContain("header");
  });

  it("header returns 3 items", async () => {
    const caller = navigationRouter.createCaller({});
    const result = await caller.header({});
    expect(result.items).toHaveLength(3);
  });
});

describe("navigationRouter (R26 error mapping)", () => {
  beforeEach(() => {
    navigationContainer.unbindAll();
    navigationContainer.load(NavigationModule);
  });

  afterEach(() => {
    navigationContainer.unbindAll();
  });

  it("translates InputParseError → BAD_REQUEST when extra fields are passed", async () => {
    const caller = navigationRouter.createCaller({});
    try {
      await caller.header({ unexpected: "field" } as unknown as Record<string, never>);
      throw new Error("expected throw");
    } catch (e) {
      expect(e).toBeInstanceOf(TRPCError);
      expect((e as TRPCError).code).toBe("BAD_REQUEST");
    }
  });

  it("translates HeaderNotFoundError → NOT_FOUND when repository returns null", async () => {
    @injectable()
    class NullHeaderRepository {
      async getHeader() {
        return null as never;
      }
    }

    navigationContainer.unbindAll();
    navigationContainer
      .bind(NAVIGATION_SYMBOLS.IHeaderRepository)
      .to(NullHeaderRepository);
    navigationContainer
      .bind(NAVIGATION_SYMBOLS.IGetHeaderUseCase)
      .toDynamicValue((ctx) =>
        getHeaderUseCase(ctx.container.get(NAVIGATION_SYMBOLS.IHeaderRepository)),
      );
    navigationContainer
      .bind(NAVIGATION_SYMBOLS.IGetHeaderController)
      .toDynamicValue((ctx) =>
        getHeaderController(ctx.container.get(NAVIGATION_SYMBOLS.IGetHeaderUseCase)),
      );

    const caller = navigationRouter.createCaller({});
    try {
      await caller.header({});
      throw new Error("expected throw");
    } catch (e) {
      expect(e).toBeInstanceOf(TRPCError);
      expect((e as TRPCError).code).toBe("NOT_FOUND");
    }
  });
});
