import { describe, it, expect } from 'vitest';
import { SponsorDashboardViewModel } from './SponsorDashboardViewModel';
import { SponsorshipViewModel } from './SponsorshipViewModel';
import { ActivityItemViewModel } from './ActivityItemViewModel';
import { RenewalAlertViewModel } from './RenewalAlertViewModel';

function makeSponsorship(overrides: Partial<any> = {}) {
  return {
    id: 's-1',
    type: 'leagues',
    entityId: 'league-1',
    entityName: 'Pro League',
    status: 'active',
    startDate: '2025-01-01',
    endDate: '2025-12-31',
    price: 5_000,
    impressions: 50_000,
    ...overrides,
  };
}

describe('SponsorDashboardViewModel', () => {
  const baseDto = {
    sponsorId: 'sp-1',
    sponsorName: 'Acme Corp',
    metrics: { totalSpend: 10_000, totalImpressions: 100_000 },
    sponsorships: {
      leagues: [makeSponsorship()],
      teams: [makeSponsorship({ id: 's-2', type: 'teams', price: 2_000, impressions: 20_000 })],
      drivers: [],
      races: [],
      platform: [],
    },
    recentActivity: [
      { id: 'a-1', type: 'impression', timestamp: '2025-01-01T00:00:00Z', metadata: {} },
    ],
    upcomingRenewals: [
      { id: 'r-1', sponsorshipId: 's-1', leagueName: 'Pro League', daysUntilRenewal: 10 },
    ],
  } as any;

  it('maps nested DTOs into view models', () => {
    const vm = new SponsorDashboardViewModel(baseDto);

    expect(vm.sponsorId).toBe(baseDto.sponsorId);
    expect(vm.sponsorName).toBe(baseDto.sponsorName);
    expect(vm.metrics).toBe(baseDto.metrics);

    expect(vm.sponsorships.leagues[0]).toBeInstanceOf(SponsorshipViewModel);
    expect(vm.sponsorships.teams[0]).toBeInstanceOf(SponsorshipViewModel);
    expect(vm.recentActivity[0]).toBeInstanceOf(ActivityItemViewModel);
    expect(vm.upcomingRenewals[0]).toBeInstanceOf(RenewalAlertViewModel);
  });

  it('computes total, active counts and investment from sponsorship buckets', () => {
    const vm = new SponsorDashboardViewModel(baseDto);

    const all = [
      ...baseDto.sponsorships.leagues,
      ...baseDto.sponsorships.teams,
    ];

    expect(vm.totalSponsorships).toBe(all.length);
    expect(vm.activeSponsorships).toBe(all.filter(s => s.status === 'active').length);
    const expectedInvestment = all
      .filter(s => s.status === 'active')
      .reduce((sum, s) => sum + s.price, 0);
    expect(vm.totalInvestment).toBe(expectedInvestment);
  });

  it('aggregates total impressions across all sponsorships', () => {
    const vm = new SponsorDashboardViewModel(baseDto);

    const all = [
      ...baseDto.sponsorships.leagues,
      ...baseDto.sponsorships.teams,
    ];

    const expectedImpressions = all.reduce((sum, s) => sum + s.impressions, 0);
    expect(vm.totalImpressions).toBe(expectedImpressions);
  });

  it('derives formatted investment, active percentage, status text and CPM', () => {
    const vm = new SponsorDashboardViewModel(baseDto);

    expect(vm.formattedTotalInvestment).toBe(`$${vm.totalInvestment.toLocaleString()}`);

    const expectedActivePercentage = Math.round((vm.activeSponsorships / vm.totalSponsorships) * 100);
    expect(vm.activePercentage).toBe(expectedActivePercentage);
    expect(vm.hasSponsorships).toBe(true);

    // statusText variants
    const noActive = new SponsorDashboardViewModel({
      ...baseDto,
      sponsorships: {
        leagues: [makeSponsorship({ status: 'expired' })],
        teams: [],
        drivers: [],
        races: [],
        platform: [],
      },
    } as any);
    expect(noActive.statusText).toBe('No active sponsorships');

    const allActive = new SponsorDashboardViewModel({
      ...baseDto,
      sponsorships: {
        leagues: [makeSponsorship()],
        teams: [],
        drivers: [],
        races: [],
        platform: [],
      },
    } as any);
    expect(allActive.statusText).toBe('All sponsorships active');

    // cost per thousand views
    expect(vm.costPerThousandViews).toBe(`$${(vm.totalInvestment / vm.totalImpressions * 1000).toFixed(2)}`);

    const zeroImpressions = new SponsorDashboardViewModel({
      ...baseDto,
      sponsorships: {
        leagues: [makeSponsorship({ impressions: 0 })],
        teams: [],
        drivers: [],
        races: [],
        platform: [],
      },
    } as any);
    expect(zeroImpressions.costPerThousandViews).toBe('$0.00');
  });

  it('exposes category data per sponsorship bucket', () => {
    const vm = new SponsorDashboardViewModel(baseDto);

    expect(vm.categoryData.leagues.count).toBe(baseDto.sponsorships.leagues.length);
    expect(vm.categoryData.leagues.impressions).toBe(
      baseDto.sponsorships.leagues.reduce((sum: number, s: any) => sum + s.impressions, 0),
    );

    expect(vm.categoryData.teams.count).toBe(baseDto.sponsorships.teams.length);
    expect(vm.categoryData.teams.impressions).toBe(
      baseDto.sponsorships.teams.reduce((sum: number, s: any) => sum + s.impressions, 0),
    );
  });

  it('handles missing sponsorship buckets gracefully', () => {
    const vm = new SponsorDashboardViewModel({
      ...baseDto,
      sponsorships: undefined,
      recentActivity: undefined,
      upcomingRenewals: undefined,
    } as any);

    expect(vm.totalSponsorships).toBe(0);
    expect(vm.activeSponsorships).toBe(0);
    expect(vm.totalInvestment).toBe(0);
    expect(vm.totalImpressions).toBe(0);
    expect(vm.activePercentage).toBe(0);
    expect(vm.hasSponsorships).toBe(false);
    expect(vm.costPerThousandViews).toBe('$0.00');
    expect(vm.recentActivity).toEqual([]);
    expect(vm.upcomingRenewals).toEqual([]);
  });
});
