/**
 * View Data Layer Tests - Dashboard Functionality
 *
 * This test file covers the view data layer for dashboard functionality.
 *
 * The view data layer is responsible for:
 * - DTO → UI model mapping
 * - Formatting, sorting, and grouping
 * - Derived fields and defaults
 * - UI-specific semantics
 *
 * This layer isolates the UI from API churn by providing a stable interface
 * between the API layer and the presentation layer.
 *
 * Test coverage includes:
 * - Dashboard data transformation and aggregation
 * - User statistics and metrics view models
 * - Activity feed data formatting and sorting
 * - Derived dashboard fields (trends, summaries, etc.)
 * - Default values and fallbacks for dashboard views
 * - Dashboard-specific formatting (dates, numbers, percentages, etc.)
 * - Data grouping and categorization for dashboard components
 * - Real-time data updates and state management
 */

import { DashboardViewDataBuilder } from '@/lib/builders/view-data/DashboardViewDataBuilder';
import { DashboardDateDisplay } from '@/lib/display-objects/DashboardDateDisplay';
import { DashboardCountDisplay } from '@/lib/display-objects/DashboardCountDisplay';
import { DashboardRankDisplay } from '@/lib/display-objects/DashboardRankDisplay';
import { DashboardConsistencyDisplay } from '@/lib/display-objects/DashboardConsistencyDisplay';
import { DashboardLeaguePositionDisplay } from '@/lib/display-objects/DashboardLeaguePositionDisplay';
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO';
import type { DashboardDriverSummaryDTO } from '@/lib/types/generated/DashboardDriverSummaryDTO';
import type { DashboardRaceSummaryDTO } from '@/lib/types/generated/DashboardRaceSummaryDTO';
import type { DashboardFeedSummaryDTO } from '@/lib/types/generated/DashboardFeedSummaryDTO';
import type { DashboardFriendSummaryDTO } from '@/lib/types/generated/DashboardFriendSummaryDTO';
import type { DashboardLeagueStandingSummaryDTO } from '@/lib/types/generated/DashboardLeagueStandingSummaryDTO';

describe('DashboardViewDataBuilder', () => {
  describe('happy paths', () => {
    it('should transform DashboardOverviewDTO to DashboardViewData correctly', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          avatarUrl: 'https://example.com/avatar.jpg',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 5,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver).toEqual({
        name: 'John Doe',
        avatarUrl: 'https://example.com/avatar.jpg',
        country: 'USA',
        rating: '1,235',
        rank: '42',
        totalRaces: '150',
        wins: '25',
        podiums: '60',
        consistency: '85%',
      });
      expect(result.nextRace).toBeNull();
      expect(result.upcomingRaces).toEqual([]);
      expect(result.leagueStandings).toEqual([]);
      expect(result.feedItems).toEqual([]);
      expect(result.friends).toEqual([]);
      expect(result.activeLeaguesCount).toBe('3');
      expect(result.friendCount).toBe('0');
      expect(result.hasUpcomingRaces).toBe(false);
      expect(result.hasLeagueStandings).toBe(false);
      expect(result.hasFeedItems).toBe(false);
      expect(result.hasFriends).toBe(false);
    });

    it('should handle missing currentDriver gracefully', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 0,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver).toEqual({
        name: '',
        avatarUrl: '',
        country: '',
        rating: '0.0',
        rank: '0',
        totalRaces: '0',
        wins: '0',
        podiums: '0',
        consistency: '0%',
      });
    });

    it('should handle null/undefined driver fields', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'Jane Smith',
          country: 'Canada',
          rating: null,
          globalRank: null,
          totalRaces: 0,
          wins: 0,
          podiums: 0,
          consistency: null,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 0,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver.rating).toBe('0');
      expect(result.currentDriver.rank).toBe('0');
      expect(result.currentDriver.consistency).toBe('0%');
    });

    it('should handle nextRace with all fields', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours from now
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: {
          id: 'race-456',
          leagueId: 'league-789',
          leagueName: 'Pro League',
          track: 'Monza',
          car: 'Ferrari 488 GT3',
          scheduledAt: futureDate.toISOString(),
          status: 'scheduled',
          isMyLeague: true,
        },
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.nextRace).not.toBeNull();
      expect(result.nextRace?.id).toBe('race-456');
      expect(result.nextRace?.track).toBe('Monza');
      expect(result.nextRace?.car).toBe('Ferrari 488 GT3');
      expect(result.nextRace?.scheduledAt).toBe(futureDate.toISOString());
      expect(result.nextRace?.isMyLeague).toBe(true);
      expect(result.nextRace?.formattedDate).toBeDefined();
      expect(result.nextRace?.formattedTime).toBeDefined();
      expect(result.nextRace?.timeUntil).toBeDefined();
    });

    it('should handle upcomingRaces with multiple races', () => {
      const now = new Date();
      const race1Date = new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000); // 2 days from now
      const race2Date = new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000); // 5 days from now

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [
          {
            id: 'race-1',
            track: 'Spa',
            car: 'Porsche 911 GT3',
            scheduledAt: race1Date.toISOString(),
            status: 'scheduled',
            isMyLeague: true,
          },
          {
            id: 'race-2',
            track: 'Nürburgring',
            car: 'Audi R8 LMS',
            scheduledAt: race2Date.toISOString(),
            status: 'scheduled',
            isMyLeague: false,
          },
        ],
        activeLeaguesCount: 2,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.upcomingRaces).toHaveLength(2);
      expect(result.upcomingRaces[0].id).toBe('race-1');
      expect(result.upcomingRaces[0].track).toBe('Spa');
      expect(result.upcomingRaces[0].isMyLeague).toBe(true);
      expect(result.upcomingRaces[1].id).toBe('race-2');
      expect(result.upcomingRaces[1].track).toBe('Nürburgring');
      expect(result.upcomingRaces[1].isMyLeague).toBe(false);
      expect(result.hasUpcomingRaces).toBe(true);
    });

    it('should handle leagueStandings with multiple leagues', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 2,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [
          {
            leagueId: 'league-1',
            leagueName: 'Rookie League',
            position: 5,
            totalDrivers: 50,
            points: 1250,
          },
          {
            leagueId: 'league-2',
            leagueName: 'Pro League',
            position: 12,
            totalDrivers: 100,
            points: 890,
          },
        ],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.leagueStandings).toHaveLength(2);
      expect(result.leagueStandings[0].leagueId).toBe('league-1');
      expect(result.leagueStandings[0].leagueName).toBe('Rookie League');
      expect(result.leagueStandings[0].position).toBe('#5');
      expect(result.leagueStandings[0].points).toBe('1,250');
      expect(result.leagueStandings[0].totalDrivers).toBe('50');
      expect(result.leagueStandings[1].leagueId).toBe('league-2');
      expect(result.leagueStandings[1].leagueName).toBe('Pro League');
      expect(result.leagueStandings[1].position).toBe('#12');
      expect(result.leagueStandings[1].points).toBe('890');
      expect(result.leagueStandings[1].totalDrivers).toBe('100');
      expect(result.hasLeagueStandings).toBe(true);
    });

    it('should handle feedItems with all fields', () => {
      const now = new Date();
      const timestamp = new Date(now.getTime() - 30 * 60 * 1000); // 30 minutes ago

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 3,
          items: [
            {
              id: 'feed-1',
              type: 'race_result',
              headline: 'Race completed',
              body: 'You finished 3rd in the Pro League race',
              timestamp: timestamp.toISOString(),
              ctaLabel: 'View Results',
              ctaHref: '/races/123',
            },
            {
              id: 'feed-2',
              type: 'league_update',
              headline: 'League standings updated',
              body: 'You moved up 2 positions',
              timestamp: timestamp.toISOString(),
            },
          ],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.feedItems).toHaveLength(2);
      expect(result.feedItems[0].id).toBe('feed-1');
      expect(result.feedItems[0].type).toBe('race_result');
      expect(result.feedItems[0].headline).toBe('Race completed');
      expect(result.feedItems[0].body).toBe('You finished 3rd in the Pro League race');
      expect(result.feedItems[0].timestamp).toBe(timestamp.toISOString());
      expect(result.feedItems[0].formattedTime).toBe('30m');
      expect(result.feedItems[0].ctaLabel).toBe('View Results');
      expect(result.feedItems[0].ctaHref).toBe('/races/123');
      expect(result.feedItems[1].id).toBe('feed-2');
      expect(result.feedItems[1].type).toBe('league_update');
      expect(result.feedItems[1].headline).toBe('League standings updated');
      expect(result.feedItems[1].body).toBe('You moved up 2 positions');
      expect(result.feedItems[1].ctaLabel).toBeUndefined();
      expect(result.feedItems[1].ctaHref).toBeUndefined();
      expect(result.hasFeedItems).toBe(true);
    });

    it('should handle friends with avatar URLs', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [
          {
            id: 'friend-1',
            name: 'Alice',
            country: 'UK',
            avatarUrl: 'https://example.com/alice.jpg',
          },
          {
            id: 'friend-2',
            name: 'Bob',
            country: 'Germany',
            avatarUrl: undefined,
          },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.friends).toHaveLength(2);
      expect(result.friends[0].id).toBe('friend-1');
      expect(result.friends[0].name).toBe('Alice');
      expect(result.friends[0].country).toBe('UK');
      expect(result.friends[0].avatarUrl).toBe('https://example.com/alice.jpg');
      expect(result.friends[1].id).toBe('friend-2');
      expect(result.friends[1].name).toBe('Bob');
      expect(result.friends[1].country).toBe('Germany');
      expect(result.friends[1].avatarUrl).toBe('');
      expect(result.friendCount).toBe('2');
      expect(result.hasFriends).toBe(true);
    });

    it('should handle empty arrays and zero counts', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 0,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.upcomingRaces).toEqual([]);
      expect(result.leagueStandings).toEqual([]);
      expect(result.feedItems).toEqual([]);
      expect(result.friends).toEqual([]);
      expect(result.activeLeaguesCount).toBe('0');
      expect(result.friendCount).toBe('0');
      expect(result.hasUpcomingRaces).toBe(false);
      expect(result.hasLeagueStandings).toBe(false);
      expect(result.hasFeedItems).toBe(false);
      expect(result.hasFriends).toBe(false);
    });
  });

  describe('data transformation', () => {
    it('should preserve all DTO fields in the output', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          avatarUrl: 'https://example.com/avatar.jpg',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 5,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver.name).toBe(dashboardDTO.currentDriver?.name);
      expect(result.currentDriver.country).toBe(dashboardDTO.currentDriver?.country);
      expect(result.currentDriver.avatarUrl).toBe(dashboardDTO.currentDriver?.avatarUrl);
      expect(result.activeLeaguesCount).toBe(dashboardDTO.activeLeaguesCount.toString());
    });

    it('should not modify the input DTO', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 5,
          items: [],
        },
        friends: [],
      };

      const originalDTO = JSON.parse(JSON.stringify(dashboardDTO));
      DashboardViewDataBuilder.build(dashboardDTO);

      expect(dashboardDTO).toEqual(originalDTO);
    });

    it('should transform all numeric fields to formatted strings', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 5,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(typeof result.currentDriver.rating).toBe('string');
      expect(typeof result.currentDriver.rank).toBe('string');
      expect(typeof result.currentDriver.totalRaces).toBe('string');
      expect(typeof result.currentDriver.wins).toBe('string');
      expect(typeof result.currentDriver.podiums).toBe('string');
      expect(typeof result.currentDriver.consistency).toBe('string');
      expect(typeof result.activeLeaguesCount).toBe('string');
      expect(typeof result.friendCount).toBe('string');
    });

    it('should handle large numbers correctly', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          rating: 999999.99,
          globalRank: 1,
          totalRaces: 10000,
          wins: 2500,
          podiums: 5000,
          consistency: 99.9,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 100,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver.rating).toBe('1,000,000');
      expect(result.currentDriver.totalRaces).toBe('10000');
      expect(result.currentDriver.wins).toBe('2500');
      expect(result.currentDriver.podiums).toBe('5000');
      expect(result.currentDriver.consistency).toBe('99.9%');
      expect(result.activeLeaguesCount).toBe('100');
    });
  });

  describe('edge cases', () => {
    it('should handle missing optional fields in driver', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          totalRaces: 100,
          wins: 20,
          podiums: 40,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.currentDriver.avatarUrl).toBe('');
      expect(result.currentDriver.rating).toBe('0.0');
      expect(result.currentDriver.rank).toBe('0');
      expect(result.currentDriver.consistency).toBe('0%');
    });

    it('should handle race with missing optional fields', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: {
          id: 'race-456',
          track: 'Monza',
          car: 'Ferrari 488 GT3',
          scheduledAt: futureDate.toISOString(),
          status: 'scheduled',
          isMyLeague: true,
        },
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.nextRace).not.toBeNull();
      expect(result.nextRace?.leagueId).toBeUndefined();
      expect(result.nextRace?.leagueName).toBeUndefined();
    });

    it('should handle feed item with missing optional fields', () => {
      const now = new Date();
      const timestamp = new Date(now.getTime() - 60 * 60 * 1000); // 1 hour ago

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 1,
          items: [
            {
              id: 'feed-1',
              type: 'notification',
              headline: 'New notification',
              timestamp: timestamp.toISOString(),
            },
          ],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.feedItems[0].body).toBeUndefined();
      expect(result.feedItems[0].ctaLabel).toBeUndefined();
      expect(result.feedItems[0].ctaHref).toBeUndefined();
    });

    it('should handle friend with missing avatarUrl', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [
          {
            id: 'friend-1',
            name: 'Alice',
            country: 'UK',
          },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.friends[0].avatarUrl).toBe('');
    });

    it('should handle league standing with null position', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [
          {
            leagueId: 'league-1',
            leagueName: 'Test League',
            position: null as any,
            totalDrivers: 50,
            points: 1000,
          },
        ],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.leagueStandings[0].position).toBe('-');
    });

    it('should handle race with empty track and car', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: {
          id: 'race-456',
          track: '',
          car: '',
          scheduledAt: futureDate.toISOString(),
          status: 'scheduled',
          isMyLeague: true,
        },
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.nextRace?.track).toBe('');
      expect(result.nextRace?.car).toBe('');
    });
  });

  describe('derived fields', () => {
    it('should correctly calculate hasUpcomingRaces', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [
          {
            id: 'race-1',
            track: 'Spa',
            car: 'Porsche',
            scheduledAt: new Date().toISOString(),
            status: 'scheduled',
            isMyLeague: true,
          },
        ],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.hasUpcomingRaces).toBe(true);
    });

    it('should correctly calculate hasLeagueStandings', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [
          {
            leagueId: 'league-1',
            leagueName: 'Test League',
            position: 5,
            totalDrivers: 50,
            points: 1000,
          },
        ],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.hasLeagueStandings).toBe(true);
    });

    it('should correctly calculate hasFeedItems', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 1,
          items: [
            {
              id: 'feed-1',
              type: 'notification',
              headline: 'Test',
              timestamp: new Date().toISOString(),
            },
          ],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.hasFeedItems).toBe(true);
    });

    it('should correctly calculate hasFriends', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [
          {
            id: 'friend-1',
            name: 'Alice',
            country: 'UK',
          },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.hasFriends).toBe(true);
    });

    it('should correctly calculate friendCount', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [
          { id: 'friend-1', name: 'Alice', country: 'UK' },
          { id: 'friend-2', name: 'Bob', country: 'Germany' },
          { id: 'friend-3', name: 'Charlie', country: 'France' },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.friendCount).toBe('3');
    });
  });
});

describe('DashboardDateDisplay', () => {
  describe('happy paths', () => {
    it('should format future date correctly', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours from now

      const result = DashboardDateDisplay.format(futureDate);

      expect(result.date).toMatch(/^[A-Za-z]{3}, [A-Za-z]{3} \d{1,2}, \d{4}$/);
      expect(result.time).toMatch(/^\d{2}:\d{2}$/);
      expect(result.relative).toBe('24h');
    });

    it('should format date less than 24 hours correctly', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 6 * 60 * 60 * 1000); // 6 hours from now

      const result = DashboardDateDisplay.format(futureDate);

      expect(result.relative).toBe('6h');
    });

    it('should format date more than 24 hours correctly', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 48 * 60 * 60 * 1000); // 2 days from now

      const result = DashboardDateDisplay.format(futureDate);

      expect(result.relative).toBe('2d');
    });

    it('should format past date correctly', () => {
      const now = new Date();
      const pastDate = new Date(now.getTime() - 24 * 60 * 60 * 1000); // 24 hours ago

      const result = DashboardDateDisplay.format(pastDate);

      expect(result.relative).toBe('Past');
    });

    it('should format current date correctly', () => {
      const now = new Date();

      const result = DashboardDateDisplay.format(now);

      expect(result.relative).toBe('Now');
    });

    it('should format date with leading zeros in time', () => {
      const date = new Date('2024-01-15T05:03:00');

      const result = DashboardDateDisplay.format(date);

      expect(result.time).toBe('05:03');
    });
  });

  describe('edge cases', () => {
    it('should handle midnight correctly', () => {
      const date = new Date('2024-01-15T00:00:00');

      const result = DashboardDateDisplay.format(date);

      expect(result.time).toBe('00:00');
    });

    it('should handle end of day correctly', () => {
      const date = new Date('2024-01-15T23:59:59');

      const result = DashboardDateDisplay.format(date);

      expect(result.time).toBe('23:59');
    });

    it('should handle different days of week', () => {
      const date = new Date('2024-01-15'); // Monday

      const result = DashboardDateDisplay.format(date);

      expect(result.date).toContain('Mon');
    });

    it('should handle different months', () => {
      const date = new Date('2024-01-15');

      const result = DashboardDateDisplay.format(date);

      expect(result.date).toContain('Jan');
    });
  });
});

describe('DashboardCountDisplay', () => {
  describe('happy paths', () => {
    it('should format positive numbers correctly', () => {
      expect(DashboardCountDisplay.format(0)).toBe('0');
      expect(DashboardCountDisplay.format(1)).toBe('1');
      expect(DashboardCountDisplay.format(100)).toBe('100');
      expect(DashboardCountDisplay.format(1000)).toBe('1000');
    });

    it('should handle null values', () => {
      expect(DashboardCountDisplay.format(null)).toBe('0');
    });

    it('should handle undefined values', () => {
      expect(DashboardCountDisplay.format(undefined)).toBe('0');
    });
  });

  describe('edge cases', () => {
    it('should handle negative numbers', () => {
      expect(DashboardCountDisplay.format(-1)).toBe('-1');
      expect(DashboardCountDisplay.format(-100)).toBe('-100');
    });

    it('should handle large numbers', () => {
      expect(DashboardCountDisplay.format(999999)).toBe('999999');
      expect(DashboardCountDisplay.format(1000000)).toBe('1000000');
    });

    it('should handle decimal numbers', () => {
      expect(DashboardCountDisplay.format(1.5)).toBe('1.5');
      expect(DashboardCountDisplay.format(100.99)).toBe('100.99');
    });
  });
});

describe('DashboardRankDisplay', () => {
  describe('happy paths', () => {
    it('should format rank correctly', () => {
      expect(DashboardRankDisplay.format(1)).toBe('1');
      expect(DashboardRankDisplay.format(42)).toBe('42');
      expect(DashboardRankDisplay.format(100)).toBe('100');
    });
  });

  describe('edge cases', () => {
    it('should handle rank 0', () => {
      expect(DashboardRankDisplay.format(0)).toBe('0');
    });

    it('should handle large ranks', () => {
      expect(DashboardRankDisplay.format(999999)).toBe('999999');
    });
  });
});

describe('DashboardConsistencyDisplay', () => {
  describe('happy paths', () => {
    it('should format consistency correctly', () => {
      expect(DashboardConsistencyDisplay.format(0)).toBe('0%');
      expect(DashboardConsistencyDisplay.format(50)).toBe('50%');
      expect(DashboardConsistencyDisplay.format(100)).toBe('100%');
    });
  });

  describe('edge cases', () => {
    it('should handle decimal consistency', () => {
      expect(DashboardConsistencyDisplay.format(85.5)).toBe('85.5%');
      expect(DashboardConsistencyDisplay.format(99.9)).toBe('99.9%');
    });

    it('should handle negative consistency', () => {
      expect(DashboardConsistencyDisplay.format(-10)).toBe('-10%');
    });
  });
});

describe('DashboardLeaguePositionDisplay', () => {
  describe('happy paths', () => {
    it('should format position correctly', () => {
      expect(DashboardLeaguePositionDisplay.format(1)).toBe('#1');
      expect(DashboardLeaguePositionDisplay.format(5)).toBe('#5');
      expect(DashboardLeaguePositionDisplay.format(100)).toBe('#100');
    });

    it('should handle null values', () => {
      expect(DashboardLeaguePositionDisplay.format(null)).toBe('-');
    });

    it('should handle undefined values', () => {
      expect(DashboardLeaguePositionDisplay.format(undefined)).toBe('-');
    });
  });

  describe('edge cases', () => {
    it('should handle position 0', () => {
      expect(DashboardLeaguePositionDisplay.format(0)).toBe('#0');
    });

    it('should handle large positions', () => {
      expect(DashboardLeaguePositionDisplay.format(999)).toBe('#999');
    });
  });
});

describe('RatingDisplay', () => {
  describe('happy paths', () => {
    it('should format rating correctly', () => {
      expect(RatingDisplay.format(0)).toBe('0');
      expect(RatingDisplay.format(1234.56)).toBe('1,235');
      expect(RatingDisplay.format(9999.99)).toBe('10,000');
    });

    it('should handle null values', () => {
      expect(RatingDisplay.format(null)).toBe('—');
    });

    it('should handle undefined values', () => {
      expect(RatingDisplay.format(undefined)).toBe('—');
    });
  });

  describe('edge cases', () => {
    it('should round down correctly', () => {
      expect(RatingDisplay.format(1234.4)).toBe('1,234');
    });

    it('should round up correctly', () => {
      expect(RatingDisplay.format(1234.6)).toBe('1,235');
    });

    it('should handle decimal ratings', () => {
      expect(RatingDisplay.format(1234.5)).toBe('1,235');
    });

    it('should handle large ratings', () => {
      expect(RatingDisplay.format(999999.99)).toBe('1,000,000');
    });
  });
});

describe('Dashboard View Data - Cross-Component Consistency', () => {
  describe('common patterns', () => {
    it('should all use consistent formatting for numeric values', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [
          {
            leagueId: 'league-1',
            leagueName: 'Test League',
            position: 5,
            totalDrivers: 50,
            points: 1250,
          },
        ],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [
          { id: 'friend-1', name: 'Alice', country: 'UK' },
          { id: 'friend-2', name: 'Bob', country: 'Germany' },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      // All numeric values should be formatted as strings
      expect(typeof result.currentDriver.rating).toBe('string');
      expect(typeof result.currentDriver.rank).toBe('string');
      expect(typeof result.currentDriver.totalRaces).toBe('string');
      expect(typeof result.currentDriver.wins).toBe('string');
      expect(typeof result.currentDriver.podiums).toBe('string');
      expect(typeof result.currentDriver.consistency).toBe('string');
      expect(typeof result.activeLeaguesCount).toBe('string');
      expect(typeof result.friendCount).toBe('string');
      expect(typeof result.leagueStandings[0].position).toBe('string');
      expect(typeof result.leagueStandings[0].points).toBe('string');
      expect(typeof result.leagueStandings[0].totalDrivers).toBe('string');
    });

    it('should all handle missing data gracefully', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 0,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      // All fields should have safe defaults
      expect(result.currentDriver.name).toBe('');
      expect(result.currentDriver.avatarUrl).toBe('');
      expect(result.currentDriver.country).toBe('');
      expect(result.currentDriver.rating).toBe('0.0');
      expect(result.currentDriver.rank).toBe('0');
      expect(result.currentDriver.totalRaces).toBe('0');
      expect(result.currentDriver.wins).toBe('0');
      expect(result.currentDriver.podiums).toBe('0');
      expect(result.currentDriver.consistency).toBe('0%');
      expect(result.nextRace).toBeNull();
      expect(result.upcomingRaces).toEqual([]);
      expect(result.leagueStandings).toEqual([]);
      expect(result.feedItems).toEqual([]);
      expect(result.friends).toEqual([]);
      expect(result.activeLeaguesCount).toBe('0');
      expect(result.friendCount).toBe('0');
    });

    it('should all preserve ISO timestamps for serialization', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
      const feedTimestamp = new Date(now.getTime() - 30 * 60 * 1000);

      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 1,
        nextRace: {
          id: 'race-1',
          track: 'Spa',
          car: 'Porsche',
          scheduledAt: futureDate.toISOString(),
          status: 'scheduled',
          isMyLeague: true,
        },
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 1,
          items: [
            {
              id: 'feed-1',
              type: 'notification',
              headline: 'Test',
              timestamp: feedTimestamp.toISOString(),
            },
          ],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      // All timestamps should be preserved as ISO strings
      expect(result.nextRace?.scheduledAt).toBe(futureDate.toISOString());
      expect(result.feedItems[0].timestamp).toBe(feedTimestamp.toISOString());
    });

    it('should all handle boolean flags correctly', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [
          {
            id: 'race-1',
            track: 'Spa',
            car: 'Porsche',
            scheduledAt: new Date().toISOString(),
            status: 'scheduled',
            isMyLeague: true,
          },
          {
            id: 'race-2',
            track: 'Monza',
            car: 'Ferrari',
            scheduledAt: new Date().toISOString(),
            status: 'scheduled',
            isMyLeague: false,
          },
        ],
        activeLeaguesCount: 1,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 0,
          items: [],
        },
        friends: [],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      expect(result.upcomingRaces[0].isMyLeague).toBe(true);
      expect(result.upcomingRaces[1].isMyLeague).toBe(false);
    });
  });

  describe('data integrity', () => {
    it('should maintain data consistency across transformations', () => {
      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          rating: 1234.56,
          globalRank: 42,
          totalRaces: 150,
          wins: 25,
          podiums: 60,
          consistency: 85,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [],
        activeLeaguesCount: 3,
        nextRace: null,
        recentResults: [],
        leagueStandingsSummaries: [],
        feedSummary: {
          notificationCount: 5,
          items: [],
        },
        friends: [
          { id: 'friend-1', name: 'Alice', country: 'UK' },
          { id: 'friend-2', name: 'Bob', country: 'Germany' },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      // Verify derived fields match their source data
      expect(result.friendCount).toBe(dashboardDTO.friends.length.toString());
      expect(result.activeLeaguesCount).toBe(dashboardDTO.activeLeaguesCount.toString());
      expect(result.hasFriends).toBe(dashboardDTO.friends.length > 0);
      expect(result.hasUpcomingRaces).toBe(dashboardDTO.upcomingRaces.length > 0);
      expect(result.hasLeagueStandings).toBe(dashboardDTO.leagueStandingsSummaries.length > 0);
      expect(result.hasFeedItems).toBe(dashboardDTO.feedSummary.items.length > 0);
    });

    it('should handle complex real-world scenarios', () => {
      const now = new Date();
      const race1Date = new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000);
      const race2Date = new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000);
      const feedTimestamp = new Date(now.getTime() - 60 * 60 * 1000);

      const dashboardDTO: DashboardOverviewDTO = {
        currentDriver: {
          id: 'driver-123',
          name: 'John Doe',
          country: 'USA',
          avatarUrl: 'https://example.com/avatar.jpg',
          rating: 2456.78,
          globalRank: 15,
          totalRaces: 250,
          wins: 45,
          podiums: 120,
          consistency: 92.5,
        },
        myUpcomingRaces: [],
        otherUpcomingRaces: [],
        upcomingRaces: [
          {
            id: 'race-1',
            leagueId: 'league-1',
            leagueName: 'Pro League',
            track: 'Spa',
            car: 'Porsche 911 GT3',
            scheduledAt: race1Date.toISOString(),
            status: 'scheduled',
            isMyLeague: true,
          },
          {
            id: 'race-2',
            track: 'Monza',
            car: 'Ferrari 488 GT3',
            scheduledAt: race2Date.toISOString(),
            status: 'scheduled',
            isMyLeague: false,
          },
        ],
        activeLeaguesCount: 2,
        nextRace: {
          id: 'race-1',
          leagueId: 'league-1',
          leagueName: 'Pro League',
          track: 'Spa',
          car: 'Porsche 911 GT3',
          scheduledAt: race1Date.toISOString(),
          status: 'scheduled',
          isMyLeague: true,
        },
        recentResults: [],
        leagueStandingsSummaries: [
          {
            leagueId: 'league-1',
            leagueName: 'Pro League',
            position: 3,
            totalDrivers: 100,
            points: 2450,
          },
          {
            leagueId: 'league-2',
            leagueName: 'Rookie League',
            position: 1,
            totalDrivers: 50,
            points: 1800,
          },
        ],
        feedSummary: {
          notificationCount: 3,
          items: [
            {
              id: 'feed-1',
              type: 'race_result',
              headline: 'Race completed',
              body: 'You finished 3rd in the Pro League race',
              timestamp: feedTimestamp.toISOString(),
              ctaLabel: 'View Results',
              ctaHref: '/races/123',
            },
            {
              id: 'feed-2',
              type: 'league_update',
              headline: 'League standings updated',
              body: 'You moved up 2 positions',
              timestamp: feedTimestamp.toISOString(),
            },
          ],
        },
        friends: [
          { id: 'friend-1', name: 'Alice', country: 'UK', avatarUrl: 'https://example.com/alice.jpg' },
          { id: 'friend-2', name: 'Bob', country: 'Germany' },
          { id: 'friend-3', name: 'Charlie', country: 'France', avatarUrl: 'https://example.com/charlie.jpg' },
        ],
      };

      const result = DashboardViewDataBuilder.build(dashboardDTO);

      // Verify all transformations
      expect(result.currentDriver.name).toBe('John Doe');
      expect(result.currentDriver.rating).toBe('2,457');
      expect(result.currentDriver.rank).toBe('15');
      expect(result.currentDriver.totalRaces).toBe('250');
      expect(result.currentDriver.wins).toBe('45');
      expect(result.currentDriver.podiums).toBe('120');
      expect(result.currentDriver.consistency).toBe('92.5%');

      expect(result.nextRace).not.toBeNull();
      expect(result.nextRace?.id).toBe('race-1');
      expect(result.nextRace?.track).toBe('Spa');
      expect(result.nextRace?.isMyLeague).toBe(true);

      expect(result.upcomingRaces).toHaveLength(2);
      expect(result.upcomingRaces[0].isMyLeague).toBe(true);
      expect(result.upcomingRaces[1].isMyLeague).toBe(false);

      expect(result.leagueStandings).toHaveLength(2);
      expect(result.leagueStandings[0].position).toBe('#3');
      expect(result.leagueStandings[0].points).toBe('2,450');
      expect(result.leagueStandings[1].position).toBe('#1');
      expect(result.leagueStandings[1].points).toBe('1,800');

      expect(result.feedItems).toHaveLength(2);
      expect(result.feedItems[0].type).toBe('race_result');
      expect(result.feedItems[0].ctaLabel).toBe('View Results');
      expect(result.feedItems[1].type).toBe('league_update');
      expect(result.feedItems[1].ctaLabel).toBeUndefined();

      expect(result.friends).toHaveLength(3);
      expect(result.friends[0].avatarUrl).toBe('https://example.com/alice.jpg');
      expect(result.friends[1].avatarUrl).toBe('');
      expect(result.friends[2].avatarUrl).toBe('https://example.com/charlie.jpg');

      expect(result.activeLeaguesCount).toBe('2');
      expect(result.friendCount).toBe('3');
      expect(result.hasUpcomingRaces).toBe(true);
      expect(result.hasLeagueStandings).toBe(true);
      expect(result.hasFeedItems).toBe(true);
      expect(result.hasFriends).toBe(true);
    });
  });
});
