import { AiServiceClient } from '../services/ai-service.client';

describe('AiServiceClient', () => {
  let client: AiServiceClient;
  const originalEnv = process.env;

  beforeEach(() => {
    process.env = { ...originalEnv, AI_SERVICE_URL: 'http://localhost:8000' };
    client = new AiServiceClient();
  });

  afterEach(() => {
    process.env = originalEnv;
    vi.restoreAllMocks();
  });

  describe('predict', () => {
    it('sends predict request to AI service', async () => {
      const mockResponse = {
        estimated_price_vnd: 5_000_000_000,
        confidence: 0.82,
        price_per_m2: 70_000_000,
        price_range_low: 4_250_000_000,
        price_range_high: 5_750_000_000,
      };

      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response(JSON.stringify(mockResponse), { status: 200 }),
      );

      const result = await client.predict({
        area: 80,
        district: 'Quận 1',
        city: 'Hồ Chí Minh',
        property_type: 'apartment',
      });

      expect(result.estimated_price_vnd).toBe(5_000_000_000);
      expect(result.confidence).toBe(0.82);
      expect(fetch).toHaveBeenCalledWith(
        'http://localhost:8000/avm/predict',
        expect.objectContaining({ method: 'POST' }),
      );
    });

    it('throws on non-OK response', async () => {
      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response('Service unavailable', { status: 503 }),
      );

      await expect(
        client.predict({
          area: 80,
          district: 'Quận 1',
          city: 'Hồ Chí Minh',
          property_type: 'apartment',
        }),
      ).rejects.toThrow('AI service /avm/predict returned 503');
    });

    it('throws on network error', async () => {
      vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('ECONNREFUSED'));

      await expect(
        client.predict({
          area: 80,
          district: 'Quận 1',
          city: 'Hồ Chí Minh',
          property_type: 'apartment',
        }),
      ).rejects.toThrow('ECONNREFUSED');
    });
  });

  describe('moderate', () => {
    it('sends moderation request and returns result', async () => {
      const mockResponse = {
        is_flagged: true,
        score: 0.7,
        flags: [
          {
            category: 'contact_info',
            severity: 'medium',
            matched_text: '0901234567',
            reason: 'Contact information detected',
          },
        ],
        cleaned_text: 'Bán nhà [REDACTED]',
      };

      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response(JSON.stringify(mockResponse), { status: 200 }),
      );

      const result = await client.moderate({
        text: 'Bán nhà liên hệ 0901234567',
        context: 'listing',
      });

      expect(result.is_flagged).toBe(true);
      expect(result.score).toBe(0.7);
      expect(result.flags).toHaveLength(1);
      expect(result.flags[0].category).toBe('contact_info');
    });

    it('returns clean result for safe text', async () => {
      const mockResponse = {
        is_flagged: false,
        score: 0,
        flags: [],
        cleaned_text: 'Bán căn hộ 80m2 Quận 1',
      };

      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response(JSON.stringify(mockResponse), { status: 200 }),
      );

      const result = await client.moderate({
        text: 'Bán căn hộ 80m2 Quận 1',
      });

      expect(result.is_flagged).toBe(false);
      expect(result.score).toBe(0);
    });
  });

  describe('isAvailable', () => {
    it('returns true when service is healthy', async () => {
      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response('{"status":"ok"}', { status: 200 }),
      );

      expect(await client.isAvailable()).toBe(true);
    });

    it('returns false when service is down', async () => {
      vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('ECONNREFUSED'));

      expect(await client.isAvailable()).toBe(false);
    });

    it('returns false when service returns error', async () => {
      vi.spyOn(globalThis, 'fetch').mockResolvedValue(
        new Response('error', { status: 500 }),
      );

      expect(await client.isAvailable()).toBe(false);
    });
  });
});
