import { EventEmitter } from 'events';

export interface GameRegistration {
  id: string;
  gameId: string;
  gameName: string;
  gameType: 'slot' | 'table' | 'card' | 'arcade' | 'puzzle' | 'skill';
  description: string;
  developer: string;
  version: string;
  status: 'draft' | 'testing' | 'approved' | 'live' | 'archived';
  releaseDate: Date;
  lastUpdated: Date;
  metadata: {
    minBet: number;
    maxBet: number;
    rtp: number; // Return to Player percentage
    volatility: 'low' | 'medium' | 'high';
    paylines?: number;
    reels?: number;
    features: string[];
    theme: string;
    tags: string[];
  };
  performance: {
    totalPlays: number;
    totalWagers: number;
    totalPayouts: number;
    averageSessionLength: number;
    playerRetention: number;
  };
  wallet: {
    enabled: boolean;
    minBalance: number;
    supportedCurrencies: string[];
  };
  deployment: {
    url: string;
    s3Key: string;
    previewUrl: string;
    testingUrl: string;
  };
}

export interface GameTemplate {
  id: string;
  templateName: string;
  genre: 'slot' | 'table' | 'card' | 'arcade' | 'puzzle' | 'skill';
  description: string;
  baseGame: GameRegistration;
  variants: GameRegistration[];
  metadata: Record<string, any>;
  documentation: string;
  createdAt: Date;
  updatedAt: Date;
  version: number;
}

export interface GameDeploymentWorkflow {
  id: string;
  gameId: string;
  status: 'pending' | 'validating' | 'testing' | 'approved' | 'deployed' | 'failed';
  steps: {
    validation: { completed: boolean; timestamp?: Date; error?: string };
    testing: { completed: boolean; timestamp?: Date; error?: string };
    approval: { completed: boolean; timestamp?: Date; approvedBy?: string };
    deployment: { completed: boolean; timestamp?: Date; error?: string };
  };
  createdAt: Date;
  completedAt?: Date;
}

class GameRegistrationService extends EventEmitter {
  private registeredGames: Map<string, GameRegistration> = new Map();
  private gameTemplates: Map<string, GameTemplate> = new Map();
  private deploymentWorkflows: Map<string, GameDeploymentWorkflow> = new Map();

  constructor() {
    super();
  }

  /**
   * Register a new game
   */
  registerGame(
    gameId: string,
    gameName: string,
    gameType: 'slot' | 'table' | 'card' | 'arcade' | 'puzzle' | 'skill',
    description: string,
    developer: string,
    metadata: any,
    deployment: any
  ): GameRegistration {
    const registration: GameRegistration = {
      id: `reg-${Date.now()}`,
      gameId,
      gameName,
      gameType,
      description,
      developer,
      version: '1.0.0',
      status: 'testing',
      releaseDate: new Date(),
      lastUpdated: new Date(),
      metadata: {
        minBet: metadata.minBet || 0.1,
        maxBet: metadata.maxBet || 100,
        rtp: metadata.rtp || 95,
        volatility: metadata.volatility || 'medium',
        paylines: metadata.paylines,
        reels: metadata.reels,
        features: metadata.features || [],
        theme: metadata.theme || 'default',
        tags: metadata.tags || [],
      },
      performance: {
        totalPlays: 0,
        totalWagers: 0,
        totalPayouts: 0,
        averageSessionLength: 0,
        playerRetention: 0,
      },
      wallet: {
        enabled: true,
        minBalance: metadata.minBalance || 0.1,
        supportedCurrencies: ['SC', 'USD'],
      },
      deployment: {
        url: deployment.url,
        s3Key: deployment.s3Key,
        previewUrl: deployment.previewUrl,
        testingUrl: deployment.testingUrl,
      },
    };

    this.registeredGames.set(gameId, registration);
    this.emit('game_registered', registration);

    return registration;
  }

  /**
   * Get registered game
   */
  getRegisteredGame(gameId: string): GameRegistration | null {
    return this.registeredGames.get(gameId) || null;
  }

  /**
   * Get all registered games
   */
  getAllRegisteredGames(status?: string): GameRegistration[] {
    const games = Array.from(this.registeredGames.values());
    if (status) {
      return games.filter((g) => g.status === status);
    }
    return games;
  }

  /**
   * Update game status
   */
  updateGameStatus(gameId: string, newStatus: string): GameRegistration | null {
    const game = this.registeredGames.get(gameId);
    if (!game) {
      return null;
    }

    game.status = newStatus as any;
    game.lastUpdated = new Date();

    this.emit('game_status_updated', { gameId, status: newStatus });

    return game;
  }

  /**
   * Update game performance metrics
   */
  updateGamePerformance(
    gameId: string,
    metrics: {
      plays?: number;
      wagers?: number;
      payouts?: number;
      sessionLength?: number;
      retention?: number;
    }
  ): GameRegistration | null {
    const game = this.registeredGames.get(gameId);
    if (!game) {
      return null;
    }

    if (metrics.plays !== undefined) {
      game.performance.totalPlays += metrics.plays;
    }
    if (metrics.wagers !== undefined) {
      game.performance.totalWagers += metrics.wagers;
    }
    if (metrics.payouts !== undefined) {
      game.performance.totalPayouts += metrics.payouts;
    }
    if (metrics.sessionLength !== undefined) {
      game.performance.averageSessionLength = metrics.sessionLength;
    }
    if (metrics.retention !== undefined) {
      game.performance.playerRetention = metrics.retention;
    }

    game.lastUpdated = new Date();
    this.emit('game_performance_updated', { gameId, metrics });

    return game;
  }

  /**
   * Create game template
   */
  createGameTemplate(
    templateName: string,
    genre: 'slot' | 'table' | 'card' | 'arcade' | 'puzzle' | 'skill',
    description: string,
    baseGame: GameRegistration,
    metadata: Record<string, any>,
    documentation: string
  ): GameTemplate {
    const template: GameTemplate = {
      id: `template-${Date.now()}`,
      templateName,
      genre,
      description,
      baseGame,
      variants: [],
      metadata,
      documentation,
      createdAt: new Date(),
      updatedAt: new Date(),
      version: 1,
    };

    this.gameTemplates.set(template.id, template);
    this.emit('template_created', template);

    return template;
  }

  /**
   * Get game template
   */
  getGameTemplate(templateId: string): GameTemplate | null {
    return this.gameTemplates.get(templateId) || null;
  }

  /**
   * Get all templates by genre
   */
  getTemplatesByGenre(genre: string): GameTemplate[] {
    return Array.from(this.gameTemplates.values()).filter((t) => t.genre === genre);
  }

  /**
   * Add variant to template
   */
  addVariantToTemplate(templateId: string, variant: GameRegistration): GameTemplate | null {
    const template = this.gameTemplates.get(templateId);
    if (!template) {
      return null;
    }

    template.variants.push(variant);
    template.updatedAt = new Date();

    this.emit('variant_added', { templateId, variant });

    return template;
  }

  /**
   * Create deployment workflow
   */
  createDeploymentWorkflow(gameId: string): GameDeploymentWorkflow {
    const workflow: GameDeploymentWorkflow = {
      id: `workflow-${Date.now()}`,
      gameId,
      status: 'pending',
      steps: {
        validation: { completed: false },
        testing: { completed: false },
        approval: { completed: false },
        deployment: { completed: false },
      },
      createdAt: new Date(),
    };

    this.deploymentWorkflows.set(workflow.id, workflow);
    this.emit('workflow_created', workflow);

    return workflow;
  }

  /**
   * Update workflow step
   */
  updateWorkflowStep(
    workflowId: string,
    step: 'validation' | 'testing' | 'approval' | 'deployment',
    completed: boolean,
    error?: string
  ): GameDeploymentWorkflow | null {
    const workflow = this.deploymentWorkflows.get(workflowId);
    if (!workflow) {
      return null;
    }

    workflow.steps[step] = {
      completed,
      timestamp: new Date(),
      error,
    };

    // Update overall status
    if (error) {
      workflow.status = 'failed';
    } else if (completed && step === 'deployment') {
      workflow.status = 'deployed';
      workflow.completedAt = new Date();
    } else if (completed && step === 'approval') {
      workflow.status = 'approved';
    } else if (completed && step === 'testing') {
      workflow.status = 'testing';
    } else if (completed && step === 'validation') {
      workflow.status = 'validating';
    }

    this.emit('workflow_updated', workflow);

    return workflow;
  }

  /**
   * Get deployment workflow
   */
  getDeploymentWorkflow(workflowId: string): GameDeploymentWorkflow | null {
    return this.deploymentWorkflows.get(workflowId) || null;
  }

  /**
   * Get game deployment status
   */
  getGameDeploymentStatus(gameId: string): GameDeploymentWorkflow | null {
    for (const workflow of this.deploymentWorkflows.values()) {
      if (workflow.gameId === gameId) {
        return workflow;
      }
    }
    return null;
  }

  /**
   * Get games by status
   */
  getGamesByStatus(status: string): GameRegistration[] {
    return Array.from(this.registeredGames.values()).filter((g) => g.status === status);
  }

  /**
   * Get top performing games
   */
  getTopPerformingGames(limit: number = 10): GameRegistration[] {
    return Array.from(this.registeredGames.values())
      .sort((a, b) => b.performance.totalPlays - a.performance.totalPlays)
      .slice(0, limit);
  }

  /**
   * Get games by type
   */
  getGamesByType(gameType: string): GameRegistration[] {
    return Array.from(this.registeredGames.values()).filter((g) => g.gameType === gameType);
  }

  /**
   * Get game statistics
   */
  getGameStatistics(gameId: string): {
    rtp: number;
    volatility: string;
    totalPlays: number;
    totalWagers: number;
    totalPayouts: number;
    winRate: number;
    averageWin: number;
  } | null {
    const game = this.registeredGames.get(gameId);
    if (!game) {
      return null;
    }

    const winRate = game.performance.totalPlays > 0 ? (game.performance.totalPayouts / game.performance.totalWagers) * 100 : 0;
    const averageWin = game.performance.totalPayouts > 0 ? game.performance.totalPayouts / game.performance.totalPlays : 0;

    return {
      rtp: game.metadata.rtp,
      volatility: game.metadata.volatility,
      totalPlays: game.performance.totalPlays,
      totalWagers: game.performance.totalWagers,
      totalPayouts: game.performance.totalPayouts,
      winRate,
      averageWin,
    };
  }

  /**
   * Publish game to live
   */
  publishGame(gameId: string): GameRegistration | null {
    const game = this.registeredGames.get(gameId);
    if (!game) {
      return null;
    }

    game.status = 'live';
    game.releaseDate = new Date();
    game.lastUpdated = new Date();

    this.emit('game_published', game);

    return game;
  }

  /**
   * Archive game
   */
  archiveGame(gameId: string): GameRegistration | null {
    const game = this.registeredGames.get(gameId);
    if (!game) {
      return null;
    }

    game.status = 'archived';
    game.lastUpdated = new Date();

    this.emit('game_archived', game);

    return game;
  }

  /**
   * Get all templates
   */
  getAllTemplates(): GameTemplate[] {
    return Array.from(this.gameTemplates.values());
  }

  /**
   * Get template statistics
   */
  getTemplateStatistics(templateId: string): {
    totalVariants: number;
    totalPlays: number;
    totalWagers: number;
    averageRTP: number;
  } | null {
    const template = this.gameTemplates.get(templateId);
    if (!template) {
      return null;
    }

    const allGames = [template.baseGame, ...template.variants];
    const totalPlays = allGames.reduce((sum, g) => sum + g.performance.totalPlays, 0);
    const totalWagers = allGames.reduce((sum, g) => sum + g.performance.totalWagers, 0);
    const averageRTP = allGames.reduce((sum, g) => sum + g.metadata.rtp, 0) / allGames.length;

    return {
      totalVariants: template.variants.length,
      totalPlays,
      totalWagers,
      averageRTP,
    };
  }
}

// Export singleton instance
export const gameRegistrationService = new GameRegistrationService();

export default GameRegistrationService;
