import { ProvinceCityDistribution } from '../../../src/domain/value-objects/province-city-distribution.vo';

describe('ProvinceCityDistribution Value Object', () => {
  describe('empty', () => {
    it('should create empty distribution', () => {
      const dist = ProvinceCityDistribution.empty();
      expect(dist.getTotal()).toBe(0);
      expect(dist.getAll()).toEqual([]);
    });
  });

  describe('fromJson', () => {
    it('should create distribution from JSON', () => {
      const json = {
        '110000': { '110100': 10, '110200': 5 },
        '120000': { '120100': 8 },
      };
      const dist = ProvinceCityDistribution.fromJson(json);

      expect(dist.getProvinceTotal('110000')).toBe(15);
      expect(dist.getProvinceTotal('120000')).toBe(8);
      expect(dist.getCityTotal('110000', '110100')).toBe(10);
    });

    it('should return empty distribution for null', () => {
      const dist = ProvinceCityDistribution.fromJson(null);
      expect(dist.getTotal()).toBe(0);
    });
  });

  describe('add', () => {
    it('should add to existing city', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('110000', '110100', 3);

      expect(dist.getCityTotal('110000', '110100')).toBe(8);
    });

    it('should add new province and city', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('120000', '120100', 3);

      expect(dist.getProvinceTotal('110000')).toBe(5);
      expect(dist.getProvinceTotal('120000')).toBe(3);
    });

    it('should be immutable', () => {
      const dist1 = ProvinceCityDistribution.empty();
      const dist2 = dist1.add('110000', '110100', 5);

      expect(dist1.getTotal()).toBe(0);
      expect(dist2.getTotal()).toBe(5);
    });
  });

  describe('getProvinceTotal', () => {
    it('should return province total', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('110000', '110200', 3);

      expect(dist.getProvinceTotal('110000')).toBe(8);
    });

    it('should return 0 for non-existent province', () => {
      const dist = ProvinceCityDistribution.empty();
      expect(dist.getProvinceTotal('999999')).toBe(0);
    });
  });

  describe('getCityTotal', () => {
    it('should return city total', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);

      expect(dist.getCityTotal('110000', '110100')).toBe(5);
    });

    it('should return 0 for non-existent city', () => {
      const dist = ProvinceCityDistribution.empty();
      expect(dist.getCityTotal('110000', '110100')).toBe(0);
    });
  });

  describe('getAll', () => {
    it('should return all province/city counts', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('110000', '110200', 3);
      dist = dist.add('120000', '120100', 8);

      const all = dist.getAll();
      expect(all.length).toBe(3);
      expect(all).toContainEqual({ provinceCode: '110000', cityCode: '110100', count: 5 });
      expect(all).toContainEqual({ provinceCode: '110000', cityCode: '110200', count: 3 });
      expect(all).toContainEqual({ provinceCode: '120000', cityCode: '120100', count: 8 });
    });
  });

  describe('getTotal', () => {
    it('should return total count', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('110000', '110200', 3);
      dist = dist.add('120000', '120100', 8);

      expect(dist.getTotal()).toBe(16);
    });
  });

  describe('toJson', () => {
    it('should convert to JSON format', () => {
      let dist = ProvinceCityDistribution.empty();
      dist = dist.add('110000', '110100', 5);
      dist = dist.add('110000', '110200', 3);

      const json = dist.toJson();
      expect(json).toEqual({
        '110000': { '110100': 5, '110200': 3 },
      });
    });
  });
});
