import { BadRequestException } from '@nestjs/common';
import { VnAdminController } from '../vn-admin.controller';

describe('VnAdminController', () => {
  let controller: VnAdminController;
  let mockVnAdmin: {
    listProvinces: ReturnType<typeof vi.fn>;
    listDistricts: ReturnType<typeof vi.fn>;
    listWards: ReturnType<typeof vi.fn>;
    resolveDistrict: ReturnType<typeof vi.fn>;
  };

  beforeEach(() => {
    mockVnAdmin = {
      listProvinces: vi.fn(),
      listDistricts: vi.fn(),
      listWards: vi.fn(),
      resolveDistrict: vi.fn(),
    };
    controller = new VnAdminController(mockVnAdmin as any);
  });

  // ── GET /reference/vn-admin/provinces ──────────────────────────────

  describe('listProvinces', () => {
    it('delegates to VnAdminService.listProvinces and returns result', async () => {
      const provinces = [
        { code: '01', name: 'Hà Nội', type: 'thanh_pho', codename: 'thanh_pho_ha_noi' },
      ];
      mockVnAdmin.listProvinces.mockResolvedValue(provinces);

      const result = await controller.listProvinces();

      expect(result).toEqual(provinces);
      expect(mockVnAdmin.listProvinces).toHaveBeenCalledOnce();
    });
  });

  // ── GET /reference/vn-admin/provinces/:code/districts ──────────────

  describe('listDistricts', () => {
    it('delegates to VnAdminService.listDistricts with the province code', async () => {
      const districts = [
        { code: '760', provinceCode: '79', name: 'Quận 1', type: 'quan', codename: 'quan_1' },
      ];
      mockVnAdmin.listDistricts.mockResolvedValue(districts);

      const result = await controller.listDistricts('79');

      expect(result).toEqual(districts);
      expect(mockVnAdmin.listDistricts).toHaveBeenCalledWith('79');
    });
  });

  // ── GET /reference/vn-admin/districts/:code/wards ──────────────────

  describe('listWards', () => {
    it('delegates to VnAdminService.listWards with the district code', async () => {
      const wards = [
        { code: '26734', districtCode: '760', name: 'Phường Bến Nghé', type: 'phuong', codename: 'phuong_ben_nghe' },
      ];
      mockVnAdmin.listWards.mockResolvedValue(wards);

      const result = await controller.listWards('760');

      expect(result).toEqual(wards);
      expect(mockVnAdmin.listWards).toHaveBeenCalledWith('760');
    });
  });

  // ── GET /reference/vn-admin/resolve-district ───────────────────────

  describe('resolveDistrict', () => {
    it('delegates to VnAdminService.resolveDistrict with name and provinceCode', async () => {
      const resolution = {
        districtCode: '760',
        isCurrent: true,
        resolvedViaAlias: false,
        aliasReason: null,
      };
      mockVnAdmin.resolveDistrict.mockResolvedValue(resolution);

      const result = await controller.resolveDistrict('Quận 1', '79');

      expect(result).toEqual(resolution);
      expect(mockVnAdmin.resolveDistrict).toHaveBeenCalledWith('Quận 1', '79');
    });

    it('delegates without provinceCode when not provided', async () => {
      const resolution = {
        districtCode: '769',
        isCurrent: false,
        resolvedViaAlias: true,
        aliasReason: 'Sáp nhập',
      };
      mockVnAdmin.resolveDistrict.mockResolvedValue(resolution);

      const result = await controller.resolveDistrict('Quận 2', undefined);

      expect(result).toEqual(resolution);
      expect(mockVnAdmin.resolveDistrict).toHaveBeenCalledWith('Quận 2', undefined);
    });

    it('throws BadRequestException when name is undefined', async () => {
      await expect(controller.resolveDistrict(undefined, undefined)).rejects.toThrow(
        BadRequestException,
      );
      expect(mockVnAdmin.resolveDistrict).not.toHaveBeenCalled();
    });

    it('throws BadRequestException when name is empty string', async () => {
      await expect(controller.resolveDistrict('', undefined)).rejects.toThrow(
        BadRequestException,
      );
      expect(mockVnAdmin.resolveDistrict).not.toHaveBeenCalled();
    });

    it('throws BadRequestException when name is whitespace only', async () => {
      await expect(controller.resolveDistrict('   ', undefined)).rejects.toThrow(
        BadRequestException,
      );
      expect(mockVnAdmin.resolveDistrict).not.toHaveBeenCalled();
    });

    it('throws BadRequestException with correct message', async () => {
      await expect(controller.resolveDistrict(undefined, undefined)).rejects.toThrow(
        'Query parameter "name" is required.',
      );
    });
  });

  // ── No auth guard (intentionally public) ───────────────────────────

  describe('public access (no auth guard)', () => {
    it('controller has no UseGuards decorator — all endpoints are public', () => {
      // VnAdminController intentionally has no @UseGuards decorator.
      // Verify by checking that the controller class metadata does not include
      // the NestJS guards metadata key.
      const guards = Reflect.getMetadata('__guards__', VnAdminController);
      expect(guards).toBeUndefined();
    });

    it('individual route handlers have no method-level guards', () => {
      const methods = ['listProvinces', 'listDistricts', 'listWards', 'resolveDistrict'] as const;
      for (const method of methods) {
        const guards = Reflect.getMetadata('__guards__', controller[method]);
        expect(guards).toBeUndefined();
      }
    });
  });
});
