import { beforeEach, describe, expect, it, vi } from "vitest";
import { ApiV1Error } from "@/lib/api-v1/errors";
import { assertAccessTokenNotExpired, requireApiV1Auth } from "./auth";

const mocks = vi.hoisted(() => ({
  createClient: vi.fn(),
  getCompanyContext: vi.fn(),
  canCompany: vi.fn(),
  createAdminClient: vi.fn(),
}));

vi.mock("@supabase/supabase-js", () => ({
  createClient: mocks.createClient,
}));

vi.mock("@/lib/company-context", () => ({
  getCompanyContext: mocks.getCompanyContext,
  canCompany: mocks.canCompany,
  companyPermissions: [],
}));

vi.mock("@/lib/supabase-server", () => ({
  createAdminClient: mocks.createAdminClient,
}));

function createJwt(payload: Record<string, unknown>) {
  const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
  const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
  return `${header}.${body}.signature`;
}

describe("api-v1 auth hardening", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    process.env.NEXT_PUBLIC_SUPABASE_URL = "https://example.supabase.co";
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = "anon-key";
    mocks.canCompany.mockReturnValue(true);
    mocks.getCompanyContext.mockResolvedValue({
      companyId: "11111111-1111-4111-8111-111111111111",
      ownerId: "22222222-2222-4222-8222-222222222222",
      tenantIds: ["11111111-1111-4111-8111-111111111111"],
      membership: { permissions: {}, role: "admin", active: true, companyId: "11111111-1111-4111-8111-111111111111" },
    });
    mocks.createAdminClient.mockReturnValue({});
  });

  it("rejeita access token expirado antes de consultar o Supabase", () => {
    const expiredToken = createJwt({
      sub: "user-1",
      exp: Math.floor(Date.now() / 1000) - 60,
    });

    expect(() => assertAccessTokenNotExpired(expiredToken)).toThrowError(ApiV1Error);
    expect(() => assertAccessTokenNotExpired(expiredToken)).toThrowError("Token expirado.");
  });

  it("bloqueia acesso cruzado entre empresas via header", async () => {
    const accessToken = createJwt({
      sub: "user-1",
      exp: Math.floor(Date.now() / 1000) + 3600,
    });

    const getUser = vi.fn().mockResolvedValue({
      data: {
        user: {
          id: "user-1",
          email: "user@example.com",
        },
      },
      error: null,
    });

    mocks.createClient.mockReturnValue({
      auth: {
        getUser,
      },
    });

    await expect(
      requireApiV1Auth(
        new Request("http://localhost/api/v1/company", {
          headers: {
            authorization: `Bearer ${accessToken}`,
            "x-ktalogu-company-id": "99999999-9999-4999-8999-999999999999",
          },
        })
      )
    ).rejects.toMatchObject({
      status: 403,
      code: "cross_company_access_denied",
    });
  });
});
