import { ForbiddenException } from '@nestjs/common';
import { AdminViewTokenController } from './admin-view-token.controller';
import { AdminViewTokenService } from './admin-view-token.service';

describe('AdminViewTokenController', () => {
  beforeEach(() => {
    process.env.ADMIN_VIEW_SECRET = 'test-admin-view-secret';
  });

  afterEach(() => {
    delete process.env.ADMIN_VIEW_SECRET;
  });

  it('발급 관리자 identity와 자동차 권한을 v2 토큰에 서명한다', async () => {
    const service = new AdminViewTokenService();
    //* 발급 경로가 최고관리자 판정을 탄다 — 그래서 발급 자체가 좁아진다(DD1a).
    const superAdmin = { isSuperAdmin: jest.fn(async () => true) };
    const controller = new AdminViewTokenController(
      service,
      {} as any,
      superAdmin as any,
    );
    const result = await controller.issue('b2c-analyze', '31', {
      admin: { role: 'admin', admId: 19 },
    } as any);

    expect(service.verify(result.token, 'b2c-analyze', 31)).toEqual({
      version: 2,
      role: 'admin',
      admId: 19,
      carView: true,
    });
  });
});

//* 영업 범위 판정의 SQL 자체는 analyze-sales-scope.mysql.spec.ts 가 잰다. 여기서는 발급 분기만 본다.
describe('영업 열람 토큰 발급 범위', () => {
  const build = (inScope: boolean) => {
    const tokenService = { issue: jest.fn(() => 'tok') };
    const analyzeRepository = {
      isOddInSalesScope: jest.fn(async () => inScope),
    };
    const superAdmin = { isSuperAdmin: jest.fn(async () => false) };
    const controller = new AdminViewTokenController(
      tokenService as any,
      analyzeRepository as any,
      superAdmin as any,
    );
    return { controller, tokenService, analyzeRepository };
  };

  const sales = { role: 'sales', sagId: 1 };
  const req = (admin: unknown) => ({ admin }) as any;

  it('담당 범위 안의 분석은 토큰을 받고 자동차 열람 claim 은 꺼진다', async () => {
    const { controller, tokenService, analyzeRepository } = build(true);

    await expect(controller.issue('analyze', '7', req(sales))).resolves.toEqual(
      {
        token: 'tok',
      },
    );
    expect(analyzeRepository.isOddInSalesScope).toHaveBeenCalledWith(7, 1);
    expect(tokenService.issue).toHaveBeenCalledWith('analyze', 7, sales, false);
  });

  it('담당 범위 밖의 분석은 403 이고 토큰을 내지 않는다', async () => {
    const { controller, tokenService } = build(false);

    await expect(controller.issue('analyze', '7', req(sales))).rejects.toThrow(
      ForbiddenException,
    );
    expect(tokenService.issue).not.toHaveBeenCalled();
  });

  it('영업에게는 analyze 스코프 밖(b2c·client)의 토큰을 범위와 무관하게 내지 않는다', async () => {
    const { controller, analyzeRepository } = build(true);

    await expect(
      controller.issue('b2c-analyze', '7', req(sales)),
    ).rejects.toThrow(ForbiddenException);
    expect(analyzeRepository.isOddInSalesScope).not.toHaveBeenCalled();
  });
});
