/**
 * Admin Service - Manages system phase, voting control, and lottery state
 */
import { redis } from '../config/redis';
import { logger } from '../utils/logger';
import type {
  AdminState,
  SystemPhase,
  VotingControlPayload,
  LotteryControlPayload,
  EmergencyResetPayload,
  MusicControlPayload,
  LotteryRound,
  LotteryWinner,
  VotingProgram,
  VoteStamp,
} from '@gala/shared/types';
import { INITIAL_ADMIN_STATE, PRIZE_CONFIG, DEFAULT_PROGRAMS } from '@gala/shared/types';

const ADMIN_STATE_KEY = 'gala:admin:state';

class AdminService {
  private state: AdminState;

  constructor() {
    this.state = { ...INITIAL_ADMIN_STATE };
  }

  /**
   * Initialize admin state from Redis or use default
   */
  async initialize(): Promise<void> {
    try {
      const savedState = await redis.get(ADMIN_STATE_KEY);
      if (savedState) {
        const parsed = JSON.parse(savedState);
        // Deep merge to ensure new fields have defaults
        this.state = {
          ...INITIAL_ADMIN_STATE,
          ...parsed,
          voting: {
            ...INITIAL_ADMIN_STATE.voting,
            ...parsed.voting,
            // Ensure programs always has default values
            programs: parsed.voting?.programs?.length > 0
              ? parsed.voting.programs
              : DEFAULT_PROGRAMS,
          },
          lottery: {
            ...INITIAL_ADMIN_STATE.lottery,
            ...parsed.lottery,
          },
          music: {
            ...INITIAL_ADMIN_STATE.music,
            ...parsed.music,
          },
        };
        logger.info('Admin state restored from Redis (merged with defaults)');
      } else {
        await this.saveState();
        logger.info('Admin state initialized with defaults');
      }
    } catch (error) {
      logger.error({ error }, 'Failed to initialize admin state');
    }
  }

  /**
   * Save current state to Redis
   */
  private async saveState(): Promise<void> {
    this.state.lastUpdated = Date.now();
    await redis.set(ADMIN_STATE_KEY, JSON.stringify(this.state));
  }

  /**
   * Get current admin state
   */
  getState(): AdminState {
    return { ...this.state };
  }

  /**
   * Check if voting is currently open
   */
  isVotingOpen(): boolean {
    return this.state.voting.subPhase === 'OPEN';
  }

  /**
   * Get voting status for error messages
   */
  getVotingStatus(): { isOpen: boolean; reason: string } {
    const subPhase = this.state.voting.subPhase;
    if (subPhase === 'OPEN') {
      return { isOpen: true, reason: '' };
    } else if (subPhase === 'PAUSED') {
      return { isOpen: false, reason: '投票已暂停' };
    } else {
      return { isOpen: false, reason: '投票通道已关闭' };
    }
  }

  /**
   * Change system phase
   */
  async setPhase(phase: SystemPhase): Promise<{ success: boolean; message?: string }> {
    try {
      this.state.systemPhase = phase;
      await this.saveState();
      logger.info({ phase }, 'System phase changed');
      return { success: true };
    } catch (error) {
      logger.error({ error, phase }, 'Failed to change phase');
      return { success: false, message: 'Failed to change phase' };
    }
  }

  /**
   * Control voting state
   */
  async controlVoting(action: VotingControlPayload['action']): Promise<{ success: boolean; message?: string }> {
    try {
      switch (action) {
        case 'open':
          if (this.state.voting.subPhase === 'OPEN') {
            return { success: false, message: 'Voting is already open' };
          }
          this.state.voting.subPhase = 'OPEN';
          this.state.voting.openedAt = Date.now();
          break;
        case 'close':
          if (this.state.voting.subPhase === 'CLOSED') {
            return { success: false, message: 'Voting is already closed' };
          }
          this.state.voting.subPhase = 'CLOSED';
          this.state.voting.closedAt = Date.now();
          break;
        case 'pause':
          if (this.state.voting.subPhase !== 'OPEN') {
            return { success: false, message: 'Voting is not open' };
          }
          this.state.voting.subPhase = 'PAUSED';
          break;
        case 'resume':
          if (this.state.voting.subPhase !== 'PAUSED') {
            return { success: false, message: 'Voting is not paused' };
          }
          this.state.voting.subPhase = 'OPEN';
          break;
      }
      await this.saveState();
      logger.info({ action, subPhase: this.state.voting.subPhase }, 'Voting control action');
      return { success: true };
    } catch (error) {
      logger.error({ error, action }, 'Failed to control voting');
      return { success: false, message: 'Failed to control voting' };
    }
  }

  // ============================================================================
  // Program Voting Control
  // ============================================================================

  /**
   * Start voting for a specific program by ID
   */
  async startProgramVoting(programId: string): Promise<{ success: boolean; message?: string }> {
    try {
      const programs = this.state.voting.programs;
      const targetProgram = programs.find(p => p.id === programId);

      if (!targetProgram) {
        return { success: false, message: 'Program not found' };
      }

      // Mark previous current program as completed
      if (this.state.voting.currentProgramId) {
        const prevProgram = programs.find(p => p.id === this.state.voting.currentProgramId);
        if (prevProgram && prevProgram.status === 'voting') {
          prevProgram.status = 'completed';
        }
      }

      // Set new current program
      targetProgram.status = 'voting';
      this.state.voting.currentProgramId = programId;
      this.state.voting.currentProgramIndex = programs.indexOf(targetProgram);
      this.state.voting.votingStartedAt = Date.now();

      await this.saveState();
      logger.info({ programId, programName: targetProgram.name }, 'Program voting started');
      return { success: true };
    } catch (error) {
      logger.error({ error, programId }, 'Failed to start program voting');
      return { success: false, message: 'Failed to start program voting' };
    }
  }

  /**
   * Move to next program in order
   */
  async nextProgram(): Promise<{ success: boolean; message?: string; programId?: string }> {
    try {
      const programs = this.state.voting.programs;

      // Find next pending program
      const nextProgram = programs.find(p => p.status === 'pending');

      if (!nextProgram) {
        return { success: false, message: 'No more programs to vote' };
      }

      const result = await this.startProgramVoting(nextProgram.id);
      if (result.success) {
        return { success: true, programId: nextProgram.id };
      }
      return result;
    } catch (error) {
      logger.error({ error }, 'Failed to move to next program');
      return { success: false, message: 'Failed to move to next program' };
    }
  }

  /**
   * Reorder programs (only pending ones can be reordered)
   */
  async reorderPrograms(programIds: string[]): Promise<{ success: boolean; message?: string }> {
    try {
      const programs = this.state.voting.programs;

      // Validate all IDs exist
      for (const id of programIds) {
        if (!programs.find(p => p.id === id)) {
          return { success: false, message: `Program ${id} not found` };
        }
      }

      // Reorder: completed/voting first, then pending in new order
      const completed = programs.filter(p => p.status === 'completed' || p.status === 'voting');
      const pending = programIds
        .filter(id => programs.find(p => p.id === id)?.status === 'pending')
        .map(id => programs.find(p => p.id === id)!);

      this.state.voting.programs = [...completed, ...pending];

      await this.saveState();
      logger.info({ newOrder: programIds }, 'Programs reordered');
      return { success: true };
    } catch (error) {
      logger.error({ error }, 'Failed to reorder programs');
      return { success: false, message: 'Failed to reorder programs' };
    }
  }

  /**
   * Toggle late catch (补投票) setting
   */
  async toggleLateCatch(enabled: boolean): Promise<{ success: boolean }> {
    this.state.voting.allowLateCatch = enabled;
    await this.saveState();
    logger.info({ allowLateCatch: enabled }, 'Late catch setting changed');
    return { success: true };
  }

  /**
   * Add a vote stamp to a program (for display on big screen)
   */
  async addVoteStamp(programId: string, userName: string, department: string, ticketType: string): Promise<{ success: boolean; stamp?: VoteStamp }> {
    const program = this.state.voting.programs.find(p => p.id === programId);
    if (!program) {
      return { success: false };
    }

    const now = new Date();
    const dateStr = `${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`;

    const stamp: VoteStamp = {
      id: `stamp_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`,
      userName,
      department,
      ticketType,
      x: 10 + Math.random() * 80,  // Random X position (10-90%)
      y: 10 + Math.random() * 80,  // Random Y position (10-90%)
      rotation: -30 + Math.random() * 60,  // Random rotation (-30 to +30 degrees)
      timestamp: Date.now(),
      date: dateStr,
    };

    if (!program.stamps) program.stamps = [];
    program.stamps.push(stamp);
    program.votes++;
    this.state.voting.totalVotes++;

    await this.saveState();
    return { success: true, stamp };
  }

  /**
   * Check if user can vote for a program
   */
  canVoteForProgram(programId: string): { canVote: boolean; reason?: string } {
    const program = this.state.voting.programs.find(p => p.id === programId);
    if (!program) {
      return { canVote: false, reason: '节目不存在' };
    }

    if (this.state.voting.subPhase !== 'OPEN') {
      return { canVote: false, reason: '投票通道未开放' };
    }

    if (program.status === 'pending') {
      return { canVote: false, reason: '该节目投票尚未开始' };
    }

    if (program.status === 'completed' && !this.state.voting.allowLateCatch) {
      return { canVote: false, reason: '该节目投票已结束' };
    }

    // Can vote for 'voting' status, or 'completed' if allowLateCatch is true
    return { canVote: true };
  }

  /**
   * Control lottery state machine
   */
  async controlLottery(
    action: LotteryControlPayload['action'],
    round?: LotteryRound
  ): Promise<{ success: boolean; message?: string; data?: { winners?: LotteryWinner[] } }> {
    try {
      switch (action) {
        case 'start_galaxy':
          if (this.state.lottery.subPhase !== 'IDLE') {
            return { success: false, message: 'Lottery is not in IDLE state' };
          }
          this.state.lottery.subPhase = 'GALAXY';
          this.state.lottery.startedAt = Date.now();
          break;

        case 'start_storm':
          if (this.state.lottery.subPhase !== 'GALAXY') {
            return { success: false, message: 'Must be in GALAXY state to start storm' };
          }
          this.state.lottery.subPhase = 'STORM';
          this.state.lottery.stormStartedAt = Date.now();
          break;

        case 'stop_reveal':
          if (this.state.lottery.subPhase !== 'STORM') {
            return { success: false, message: 'Must be in STORM state to reveal' };
          }
          // Pick random winners (simplified - in production would use database)
          const winners = this.pickRandomWinners();
          this.state.lottery.subPhase = 'REVEAL';
          this.state.lottery.currentWinners = winners;
          // After reveal animation, set to COMPLETE
          setTimeout(() => {
            this.state.lottery.subPhase = 'COMPLETE';
            this.saveState();
          }, 3000);
          await this.saveState();
          return { success: true, data: { winners } };

        case 'next_round':
          if (this.state.lottery.subPhase !== 'COMPLETE') {
            return { success: false, message: 'Current round not complete' };
          }
          if (this.state.lottery.round >= 4) {
            return { success: false, message: 'Already at final round' };
          }
          const nextRound = (this.state.lottery.round + 1) as LotteryRound;
          const prizeConfig = PRIZE_CONFIG.find(p => p.round === nextRound);
          this.state.lottery.round = nextRound;
          this.state.lottery.subPhase = 'IDLE';
          this.state.lottery.currentWinners = [];
          this.state.lottery.stormStartedAt = undefined;
          if (prizeConfig) {
            this.state.lottery.prizeLevel = prizeConfig.level;
            this.state.lottery.prizeName = prizeConfig.name;
            this.state.lottery.winnerCount = prizeConfig.winnerCount;
          }
          break;

        case 'reset':
          this.state.lottery = {
            round: 1,
            subPhase: 'IDLE',
            prizeLevel: '特等奖',
            prizeName: 'iPhone 16 Pro Max',
            winnerCount: 1,
            currentWinners: [],
          };
          break;
      }
      await this.saveState();
      logger.info({ action, lotteryState: this.state.lottery }, 'Lottery control action');
      return { success: true };
    } catch (error) {
      logger.error({ error, action }, 'Failed to control lottery');
      return { success: false, message: 'Failed to control lottery' };
    }
  }

  /**
   * Pick random winners (simplified implementation)
   */
  private pickRandomWinners(): LotteryWinner[] {
    const prizeConfig = PRIZE_CONFIG.find(p => p.round === this.state.lottery.round);
    const count = prizeConfig?.winnerCount || 1;

    // Demo winners for testing
    const demoNames = [
      { id: 'w1', name: '张明', department: '技术部' },
      { id: 'w2', name: '李华', department: '市场部' },
      { id: 'w3', name: '王强', department: '产品部' },
      { id: 'w4', name: '赵丽', department: '设计部' },
      { id: 'w5', name: '刘伟', department: '运营部' },
      { id: 'w6', name: '陈晨', department: '财务部' },
      { id: 'w7', name: '周杰', department: '人事部' },
      { id: 'w8', name: '吴欣', department: '销售部' },
      { id: 'w9', name: '郑雪', department: '技术部' },
      { id: 'w10', name: '孙浩', department: '市场部' },
    ];

    // Shuffle and pick
    const shuffled = [...demoNames].sort(() => Math.random() - 0.5);
    return shuffled.slice(0, count);
  }

  /**
   * Emergency reset
   */
  async emergencyReset(
    scope: EmergencyResetPayload['scope'],
    confirmCode: string
  ): Promise<{ success: boolean; message?: string }> {
    if (confirmCode !== 'RESET') {
      return { success: false, message: 'Invalid confirmation code' };
    }

    try {
      if (scope === 'all' || scope === 'voting') {
        this.state.voting = {
          ...INITIAL_ADMIN_STATE.voting,
          programs: DEFAULT_PROGRAMS.map(p => ({ ...p, votes: 0, stamps: [] })),
        };
        // Clear voting data in Redis
        await redis.del('gala:votes:*');
      }

      if (scope === 'all' || scope === 'lottery') {
        this.state.lottery = {
          round: 1,
          subPhase: 'IDLE',
          prizeLevel: '特等奖',
          prizeName: 'iPhone 16 Pro Max',
          winnerCount: 1,
          currentWinners: [],
        };
      }

      if (scope === 'all') {
        this.state.systemPhase = 'IDLE';
        this.state.music = {
          isPlaying: false,
          track: 'none',
          volume: 0.7,
        };
      }

      await this.saveState();
      logger.warn({ scope }, 'Emergency reset executed');
      return { success: true };
    } catch (error) {
      logger.error({ error, scope }, 'Failed to execute emergency reset');
      return { success: false, message: 'Failed to execute emergency reset' };
    }
  }

  /**
   * Control music
   */
  async controlMusic(
    action: MusicControlPayload['action'],
    track?: MusicControlPayload['track']
  ): Promise<{ success: boolean; message?: string }> {
    try {
      switch (action) {
        case 'play':
          this.state.music.isPlaying = true;
          if (track) this.state.music.track = track;
          break;
        case 'stop':
          this.state.music.isPlaying = false;
          break;
        case 'change_track':
          if (track) this.state.music.track = track;
          break;
      }
      await this.saveState();
      logger.info({ action, musicState: this.state.music }, 'Music control action');
      return { success: true };
    } catch (error) {
      logger.error({ error, action }, 'Failed to control music');
      return { success: false, message: 'Failed to control music' };
    }
  }

  /**
   * Update total vote count
   */
  async updateTotalVotes(count: number): Promise<void> {
    this.state.voting.totalVotes = count;
    await this.saveState();
  }
}

export const adminService = new AdminService();
