/**
 * Extension Systems Tests
 * Tests for mobile app, live streaming, and blockchain rewards
 */

import { describe, it, expect, beforeEach } from 'vitest';
import {
  createOfflineGameState,
  addOfflineGamePlay,
  getOfflinePlaysPendingSync,
  markOfflinePlaysAsSynced,
  compareVersions,
  isUpdateRequired,
  parseDeepLink,
  createCrashReport,
  type OfflineGameState,
} from '../mobile/mobileAppConfig.ts';
import {
  createLiveStream,
  startLiveStream,
  endLiveStream,
  addStreamDonation,
  addStreamChatMessage,
  calculateStreamMetrics,
  createTournamentStream,
  addFeaturedPlayerToStream,
  calculateStreamAnalytics,
  createScheduledStream,
  getUpcomingStreams,
  getStreamRecommendations,
} from './liveStreamingSystem';
import {
  connectCryptoWallet,
  verifyWalletOwnership,
  createBlockchainReward,
  processBlockchainReward,
  createNFTCollectible,
  listNFTForSale,
  delistNFT,
  getNFTRarityMultiplier,
  calculateNFTValue,
  createCryptoTransaction,
  confirmCryptoTransaction,
  getCryptoRewardTier,
  calculateCryptoRewards,
  createStakingPosition,
  claimStakingRewards,
  calculateCryptoPortfolio,
} from './blockchainRewardsSystem';

describe('Extension Systems', () => {
  describe('Mobile App System', () => {
    let gameState: OfflineGameState;

    beforeEach(() => {
      gameState = createOfflineGameState('game1');
    });

    it('should create offline game state', () => {
      expect(gameState.gameId).toBe('game1');
      expect(gameState.plays).toHaveLength(0);
      expect(gameState.isSynced).toBe(true);
    });

    it('should compare versions correctly', () => {
      expect(compareVersions('1.0.0', '1.0.0')).toBe(0);
      expect(compareVersions('2.0.0', '1.0.0')).toBe(1);
      expect(compareVersions('1.0.0', '2.0.0')).toBe(-1);
      expect(compareVersions('1.1.0', '1.0.0')).toBe(1);
    });

    it('should check if update is required', () => {
      expect(isUpdateRequired('1.0.0', '1.0.0')).toBe(false);
      expect(isUpdateRequired('0.9.0', '1.0.0')).toBe(true);
      expect(isUpdateRequired('1.1.0', '1.0.0')).toBe(false);
    });

    it('should parse deep links', () => {
      const link = parseDeepLink('coinkrazy://game/game1?bonus=true');
      expect(link).toBeDefined();
      expect(link?.host).toBe('game');
      expect(link?.parameters.bonus).toBe('true');
    });

    it('should create crash report', () => {
      const error = new Error('Test error');
      const deviceInfo = {
        osVersion: '14.0',
        deviceModel: 'iPhone 12',
        screenSize: '390x844',
        locale: 'en_US',
        timezone: 'UTC',
      };

      const report = createCrashReport(error, deviceInfo, '1.0.0', 1);

      expect(report.errorMessage).toBe('Test error');
      expect(report.deviceInfo.osVersion).toBe('14.0');
      expect(report.appVersion).toBe('1.0.0');
    });
  });

  describe('Live Streaming System', () => {
    let stream: any;

    beforeEach(() => {
      stream = createLiveStream(1, 'streamer1', 'Tournament Stream', 'Watch the tournament', 'twitch', 'tournament', 'gaming');
    });

    it('should create live stream', () => {
      expect(stream.username).toBe('streamer1');
      expect(stream.platform).toBe('twitch');
      expect(stream.status).toBe('scheduled');
    });

    it('should start live stream', () => {
      startLiveStream(stream);
      expect(stream.status).toBe('live');
    });

    it('should end live stream', () => {
      startLiveStream(stream);
      endLiveStream(stream);
      expect(stream.status).toBe('ended');
      expect(stream.duration).toBeDefined();
    });

    it('should add stream donation', () => {
      startLiveStream(stream);
      const donation = addStreamDonation(stream, 2, 'donor1', 50, 'USD', 'Great stream!', 'twitch');

      expect(donation.amount).toBe(50);
      expect(stream.earnings).toBe(50);
    });

    it('should add chat message', () => {
      startLiveStream(stream);
      const chat = addStreamChatMessage(stream, 2, 'viewer1', 'Nice gameplay!', 'twitch');

      expect(chat.message).toBe('Nice gameplay!');
      expect(chat.isStreamer).toBe(false);
    });

    it('should calculate stream metrics', () => {
      startLiveStream(stream);
      const donations = [addStreamDonation(stream, 2, 'donor1', 50, 'USD', 'Great!', 'twitch')];
      const chats = [addStreamChatMessage(stream, 2, 'viewer1', 'Nice!', 'twitch')];
      const viewers = [
        { userId: 2, joinTime: new Date(), leaveTime: new Date(Date.now() + 60000) },
      ];

      const metrics = calculateStreamMetrics(stream, donations, chats, viewers);

      expect(metrics.totalViewers).toBe(stream.viewers);
      expect(metrics.donations).toBe(1);
      expect(metrics.donationAmount).toBe(50);
    });

    it('should create tournament stream', () => {
      const tstream = createTournamentStream('t1', 'Tournament 1', 1, 'streamer1', 'twitch');
      expect(tstream.tournamentId).toBe('t1');
      expect(tstream.status).toBe('scheduled');
    });

    it('should add featured player to stream', () => {
      const tstream = createTournamentStream('t1', 'Tournament 1', 1, 'streamer1', 'twitch');
      addFeaturedPlayerToStream(tstream, 2);
      expect(tstream.featuredPlayers).toContain(2);
    });

    it('should get upcoming streams', () => {
      const now = new Date();
      const future = new Date(now.getTime() + 12 * 60 * 60 * 1000);
      const scheduled = createScheduledStream(1, 'streamer1', 'Future Stream', future, 'twitch');

      const upcoming = getUpcomingStreams([scheduled], 24);
      expect(upcoming.length).toBe(1);
    });

    it('should get stream recommendations', () => {
      const stream1 = createLiveStream(1, 'streamer1', 'Tournament', 'Watch', 'twitch', 'tournament', 'gaming');
      stream1.status = 'live';
      stream1.viewers = 500;

      const recommendations = getStreamRecommendations([stream1], {
        categories: ['gaming'],
        platforms: ['twitch'],
      });

      expect(recommendations.length).toBeGreaterThan(0);
    });
  });

  describe('Blockchain Rewards System', () => {
    let wallet: any;

    beforeEach(() => {
      wallet = connectCryptoWallet(1, '0x1234567890123456789012345678901234567890', 'ethereum');
    });

    it('should connect crypto wallet', () => {
      expect(wallet.address).toBe('0x1234567890123456789012345678901234567890');
      expect(wallet.network).toBe('ethereum');
      expect(wallet.isVerified).toBe(false);
    });

    it('should verify wallet ownership', () => {
      const verified = verifyWalletOwnership(wallet, 'signature');
      expect(verified).toBe(true);
      expect(wallet.isVerified).toBe(true);
    });

    it('should create blockchain reward', () => {
      const reward = createBlockchainReward(1, 'token', 100, 'CKZ', 'ethereum', wallet.address);

      expect(reward.amount).toBe(100);
      expect(reward.status).toBe('pending');
    });

    it('should process blockchain reward', () => {
      const reward = createBlockchainReward(1, 'token', 100, 'CKZ', 'ethereum', wallet.address);
      processBlockchainReward(reward, '0xabc123');

      expect(reward.status).toBe('confirmed');
      expect(reward.transactionHash).toBe('0xabc123');
    });

    it('should create NFT collectible', () => {
      const nft = createNFTCollectible(
        1,
        '1',
        'Legendary Trophy',
        'Tournament winner NFT',
        'https://example.com/nft.png',
        'legendary',
        '0xnftcontract',
        'ethereum',
        1000
      );

      expect(nft.rarity).toBe('legendary');
      expect(nft.value).toBe(1000);
    });

    it('should list NFT for sale', () => {
      const nft = createNFTCollectible(1, '1', 'Trophy', 'NFT', 'url', 'rare', 'contract', 'ethereum', 500);
      listNFTForSale(nft, 750);

      expect(nft.isListed).toBe(true);
      expect(nft.listingPrice).toBe(750);
    });

    it('should get NFT rarity multiplier', () => {
      expect(getNFTRarityMultiplier('common')).toBe(1);
      expect(getNFTRarityMultiplier('legendary')).toBe(10);
      expect(getNFTRarityMultiplier('rare')).toBe(2.5);
    });

    it('should calculate NFT value', () => {
      const value = calculateNFTValue(100, 'rare', 1.5);
      expect(value).toBe(100 * 2.5 * 1.5);
    });

    it('should create crypto transaction', () => {
      const tx = createCryptoTransaction(1, wallet.address, 'ethereum', 'deposit', 100, 'CKZ', '0xabc123');

      expect(tx.type).toBe('deposit');
      expect(tx.status).toBe('pending');
    });

    it('should confirm crypto transaction', () => {
      const tx = createCryptoTransaction(1, wallet.address, 'ethereum', 'deposit', 100, 'CKZ', '0xabc123');
      confirmCryptoTransaction(tx, 21000, 50);

      expect(tx.status).toBe('confirmed');
      expect(tx.gasUsed).toBe(21000);
    });

    it('should get crypto reward tier', () => {
      const tier = getCryptoRewardTier(5000);
      expect(tier.tier).toBe('gold');
    });

    it('should calculate crypto rewards', () => {
      const rewards = calculateCryptoRewards(1000, 5000);
      expect(rewards.tokens).toBeGreaterThan(0);
    });

    it('should create staking position', () => {
      const stake = createStakingPosition(1, wallet.address, 1000, 30, 10);

      expect(stake.stakedAmount).toBe(1000);
      expect(stake.isActive).toBe(true);
      expect(stake.rewards).toBeGreaterThan(0);
    });

    it('should claim staking rewards', () => {
      const stake = createStakingPosition(1, wallet.address, 1000, 1, 10);
      // Move end time to past
      stake.endTime = new Date(Date.now() - 1000);

      const rewards = claimStakingRewards(stake);

      expect(rewards).toBeGreaterThan(0);
      expect(stake.isActive).toBe(false);
    });

    it('should calculate crypto portfolio', () => {
      wallet.tokenBalance = 1000;
      const nft = createNFTCollectible(1, '1', 'Trophy', 'NFT', 'url', 'rare', 'contract', 'ethereum', 500);
      const stake = createStakingPosition(1, wallet.address, 2000, 30, 10);

      const portfolio = calculateCryptoPortfolio(wallet, [nft], [stake]);

      expect(portfolio.userId).toBe(1);
      expect(portfolio.totalValue).toBeGreaterThan(0);
    });
  });

  describe('Cross-System Integration', () => {
    it('should integrate mobile offline gameplay with blockchain rewards', () => {
      const gameState = createOfflineGameState('game1');
      const wallet = connectCryptoWallet(1, '0x1234567890123456789012345678901234567890', 'ethereum');

      // Simulate offline plays
      const play1 = addOfflineGamePlay(gameState, 10, 50);
      const play2 = addOfflineGamePlay(gameState, 20, 100);

      const pendingPlays = getOfflinePlaysPendingSync(gameState);
      expect(pendingPlays.length).toBe(2);

      // Award crypto rewards for plays
      const totalWinnings = pendingPlays.reduce((sum, p) => sum + p.result, 0);
      const reward = createBlockchainReward(1, 'token', totalWinnings / 10, 'CKZ', 'ethereum', wallet.address);

      expect(reward.amount).toBeGreaterThan(0);
    });

    it('should integrate streaming with NFT rewards', () => {
      const stream = createLiveStream(1, 'streamer1', 'Tournament', 'Watch', 'twitch', 'tournament', 'gaming');
      startLiveStream(stream);

      // Add donations
      const donation = addStreamDonation(stream, 2, 'donor1', 100, 'USD', 'Great stream!', 'twitch');

      // Award NFT for top donor
      const nft = createNFTCollectible(
        2,
        'donor_nft_1',
        'Top Donor NFT',
        'Awarded for donation',
        'url',
        'rare',
        'contract',
        'ethereum',
        250
      );

      expect(nft.userId).toBe(2);
      expect(nft.value).toBeGreaterThan(0);
    });
  });
});
