/**
 * Repository tests for referrals module — in-memory datastore.
 */

import { describe, it, expect, beforeEach, afterAll } from 'vitest';
import { MemoryDatastoreProvider } from '@bytelyst/datastore';
import { setProvider, _resetDatastoreProvider } from '../../lib/datastore.js';
import {
  listAll,
  getByReferrer,
  getByReferredEmail,
  getById,
  create,
  update,
  countReferrals,
} from './repository.js';
import type { ReferralDoc } from './types.js';

const baseReferral: ReferralDoc = {
  id: 'ref_1',
  productId: 'lysnrai',
  referrerId: 'user_1',
  referrerEmail: 'referrer@example.com',
  referredUserId: null,
  referredEmail: 'new@example.com',
  status: 'pending',
  referrerRewardTokens: 1000,
  referredRewardTokens: 500,
  referrerRewarded: false,
  referredRewarded: false,
  createdAt: '2026-02-16T00:00:00Z',
  completedAt: null,
};

describe('referrals repository', () => {
  beforeEach(() => {
    setProvider(new MemoryDatastoreProvider());
  });

  afterAll(() => {
    _resetDatastoreProvider();
  });

  describe('listAll', () => {
    it('returns referrals', async () => {
      await create(baseReferral);
      const result = await listAll(100, 0, 'lysnrai');
      expect(result).toHaveLength(1);
      expect(result[0]!.id).toBe('ref_1');
    });

    it('returns empty array when no referrals', async () => {
      const result = await listAll(100, 0, 'lysnrai');
      expect(result).toEqual([]);
    });
  });

  describe('getByReferrer', () => {
    it('returns referrals for referrer', async () => {
      await create(baseReferral);
      const result = await getByReferrer('user_1', 'lysnrai');
      expect(result).toHaveLength(1);
      expect(result[0]!.referrerId).toBe('user_1');
    });
  });

  describe('getByReferredEmail', () => {
    it('returns referral when found', async () => {
      await create(baseReferral);
      const result = await getByReferredEmail('new@example.com', 'lysnrai');
      expect(result).toEqual(baseReferral);
    });

    it('returns null when not found', async () => {
      const result = await getByReferredEmail('none@example.com', 'lysnrai');
      expect(result).toBeNull();
    });
  });

  describe('getById', () => {
    it('returns referral when found', async () => {
      await create(baseReferral);
      const result = await getById('ref_1', 'user_1');
      expect(result).toEqual(baseReferral);
    });

    it('returns null when not found', async () => {
      const result = await getById('nonexistent', 'user_1');
      expect(result).toBeNull();
    });
  });

  describe('create', () => {
    it('creates and returns referral', async () => {
      const result = await create(baseReferral);
      expect(result).toEqual(baseReferral);
    });
  });

  describe('update', () => {
    it('merges updates and returns referral', async () => {
      await create(baseReferral);
      const result = await update('ref_1', 'user_1', { status: 'signed_up' });
      expect(result).not.toBeNull();
      expect(result!.status).toBe('signed_up');
    });

    it('returns null when not found', async () => {
      const result = await update('nonexistent', 'user_1', { status: 'signed_up' });
      expect(result).toBeNull();
    });
  });

  describe('countReferrals', () => {
    it('returns counts', async () => {
      await create(baseReferral);
      await create({ ...baseReferral, id: 'ref_2', status: 'signed_up' });
      await create({ ...baseReferral, id: 'ref_3', status: 'rewarded' });
      const result = await countReferrals('lysnrai');
      expect(result.total).toBe(3);
      expect(result.completed).toBe(2); // signed_up + rewarded
      expect(result.rewarded).toBe(1);
    });

    it('returns zeros when no data', async () => {
      const result = await countReferrals('lysnrai');
      expect(result).toEqual({ total: 0, completed: 0, rewarded: 0 });
    });
  });
});
