import type { PrismaService } from '@modules/shared';
import { AnalyzeIndustrialLocationHandler } from '../queries/analyze-industrial-location/analyze-industrial-location.handler';
import { AnalyzeIndustrialLocationQuery } from '../queries/analyze-industrial-location/analyze-industrial-location.query';

describe('AnalyzeIndustrialLocationHandler', () => {
  let handler: AnalyzeIndustrialLocationHandler;
  let mockPrisma: { $queryRaw: ReturnType<typeof vi.fn> };

  const nearbyParks = [
    {
      id: 'park-1',
      name: 'KCN Mỹ Phước',
      province: 'Bình Dương',
      region: 'SOUTH',
      distanceKm: 2.5,
      occupancyRate: 85,
      landRentUsdM2Year: 120,
      infrastructure: {
        electricity: '110kV dedicated',
        water: 'Industrial water plant',
        wastewater: 'Central treatment',
        telecom: 'Fiber optic',
      },
      connectivity: {
        nearestPort: { name: 'Cát Lái Port', distanceKm: 35 },
        airport: { name: 'Tân Sơn Nhất', distanceKm: 25 },
        highway: { name: 'QL13', distanceKm: 1 },
      },
      incentives: {
        taxHoliday: '4 years',
        importDuty: 'Exempted for raw materials',
        landRentReduction: '50% first 5 years',
      },
      targetIndustries: ['Electronics', 'Automotive'],
    },
    {
      id: 'park-2',
      name: 'KCN Bàu Bàng',
      province: 'Bình Dương',
      region: 'SOUTH',
      distanceKm: 8.3,
      occupancyRate: 60,
      landRentUsdM2Year: 100,
      infrastructure: null,
      connectivity: null,
      incentives: null,
      targetIndustries: ['Logistics'],
    },
  ];

  beforeEach(() => {
    mockPrisma = { $queryRaw: vi.fn().mockResolvedValue(nearbyParks) };
    handler = new AnalyzeIndustrialLocationHandler(mockPrisma as unknown as PrismaService);
  });

  it('returns analysis with overall score', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.overall_score).toBeGreaterThanOrEqual(0);
    expect(result.overall_score).toBeLessThanOrEqual(100);
  });

  it('returns nearby parks sorted by distance', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.nearby_parks).toHaveLength(2);
    expect(result.nearby_parks[0]!.name).toBe('KCN Mỹ Phước');
    expect(result.nearby_parks[0]!.distanceKm).toBe(2.5);
  });

  it('extracts connectivity from nearest park', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.connectivity.nearest_port).toEqual({ name: 'Cát Lái Port', distanceKm: 35 });
    expect(result.connectivity.nearest_airport).toEqual({ name: 'Tân Sơn Nhất', distanceKm: 25 });
    expect(result.connectivity.nearest_highway).toEqual({ name: 'QL13', distanceKm: 1 });
  });

  it('extracts infrastructure from nearest park', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.infrastructure.power_availability).toBe('110kV dedicated');
    expect(result.infrastructure.water_supply).toBe('Industrial water plant');
    expect(result.infrastructure.wastewater_treatment).toBe('Central treatment');
    expect(result.infrastructure.telecom).toBe('Fiber optic');
  });

  it('gathers incentives from target park', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.incentives.length).toBeGreaterThan(0);
    expect(result.incentives.some((i) => i.includes('Tax holiday'))).toBe(true);
  });

  it('returns labor market estimates for SOUTH region', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.labor_market.worker_pool_radius_30km).toBe(500_000);
    expect(result.labor_market.average_wage_usd).toBe(350);
    expect(result.labor_market.nearby_universities.length).toBeGreaterThan(0);
  });

  it('matches specific park when parkName provided', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67, 'Bàu Bàng');
    const result = await handler.execute(query);

    expect(result.connectivity).toEqual({});
    expect(result.infrastructure).toEqual({});
  });

  it('adds risk when target industry not found in nearby parks', async () => {
    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67, undefined, 'Pharmaceuticals');
    const result = await handler.execute(query);

    expect(result.risks.some((r) => r.includes('Pharmaceuticals'))).toBe(true);
  });

  it('handles empty nearby parks gracefully', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.nearby_parks).toHaveLength(0);
    expect(result.risks.some((r) => r.includes('No industrial parks'))).toBe(true);
    expect(result.overall_score).toBeLessThan(70);
  });

  it('adds high occupancy risk when avg > 90%', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([
      { ...nearbyParks[0], occupancyRate: 95 },
      { ...nearbyParks[1], occupancyRate: 92 },
    ]);

    const query = new AnalyzeIndustrialLocationQuery(11.05, 106.67);
    const result = await handler.execute(query);

    expect(result.risks.some((r) => r.includes('High area occupancy'))).toBe(true);
  });
});
