import { ReferralChain } from '../../../src/domain/value-objects/referral-chain.vo';

describe('ReferralChain Value Object', () => {
  describe('create', () => {
    it('should create empty chain when no referrer', () => {
      const chain = ReferralChain.create(null);
      expect(chain.chain).toEqual([]);
      expect(chain.depth).toBe(0);
    });

    it('should create chain with referrer', () => {
      const chain = ReferralChain.create(100n);
      expect(chain.chain).toEqual([100n]);
      expect(chain.depth).toBe(1);
    });

    it('should create chain with parent chain', () => {
      const parentChain = [200n, 300n, 400n];
      const chain = ReferralChain.create(100n, parentChain);
      expect(chain.chain).toEqual([100n, 200n, 300n, 400n]);
      expect(chain.depth).toBe(4);
    });

    it('should truncate chain to MAX_DEPTH', () => {
      const parentChain = [2n, 3n, 4n, 5n, 6n, 7n, 8n, 9n, 10n, 11n];
      const chain = ReferralChain.create(1n, parentChain);
      expect(chain.chain.length).toBe(10);
      expect(chain.chain[0]).toBe(1n);
      expect(chain.chain[9]).toBe(10n);
    });
  });

  describe('fromArray', () => {
    it('should create chain from array', () => {
      const chain = ReferralChain.fromArray([1n, 2n, 3n]);
      expect(chain.chain).toEqual([1n, 2n, 3n]);
    });

    it('should throw error if array exceeds MAX_DEPTH', () => {
      const longArray = Array.from({ length: 11 }, (_, i) => BigInt(i + 1));
      expect(() => ReferralChain.fromArray(longArray)).toThrow('推荐链深度不能超过 10');
    });
  });

  describe('empty', () => {
    it('should create empty chain', () => {
      const chain = ReferralChain.empty();
      expect(chain.chain).toEqual([]);
      expect(chain.depth).toBe(0);
    });
  });

  describe('directReferrer', () => {
    it('should return direct referrer', () => {
      const chain = ReferralChain.create(100n, [200n, 300n]);
      expect(chain.directReferrer).toBe(100n);
    });

    it('should return null for empty chain', () => {
      const chain = ReferralChain.empty();
      expect(chain.directReferrer).toBeNull();
    });
  });

  describe('getReferrerAtLevel', () => {
    it('should return referrer at specified level', () => {
      const chain = ReferralChain.fromArray([100n, 200n, 300n]);
      expect(chain.getReferrerAtLevel(0)).toBe(100n);
      expect(chain.getReferrerAtLevel(1)).toBe(200n);
      expect(chain.getReferrerAtLevel(2)).toBe(300n);
    });

    it('should return null for out of bounds level', () => {
      const chain = ReferralChain.fromArray([100n, 200n]);
      expect(chain.getReferrerAtLevel(5)).toBeNull();
    });
  });

  describe('getAllAncestors', () => {
    it('should return all ancestors', () => {
      const chain = ReferralChain.fromArray([100n, 200n, 300n]);
      expect(chain.getAllAncestors()).toEqual([100n, 200n, 300n]);
    });

    it('should return copy of array', () => {
      const chain = ReferralChain.fromArray([100n, 200n]);
      const ancestors = chain.getAllAncestors();
      ancestors.push(999n);
      expect(chain.getAllAncestors()).toEqual([100n, 200n]);
    });
  });
});
