import { Component, DestroyRef, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ChessBoardComponent } from '../../components/chess-board/chess-board.component';
import { TournamentStreamService } from '../../services/tournament-stream.service';
import { GameClock, GameStateSnapshot, GameStreamEvent, GameStatus } from '../../models/tournament.models';
import { environment } from '../../../environments/environment';

const INITIAL_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';

@Component({
  selector: 'app-tournament-watch',
  standalone: true,
  imports: [CommonModule, RouterLink, ChessBoardComponent],
  templateUrl: './tournament-watch.component.html',
  styleUrl: './tournament-watch.component.css'
})
export class TournamentWatchComponent implements OnInit {
  private readonly route = inject(ActivatedRoute);
  private readonly destroyRef = inject(DestroyRef);
  private readonly stream = inject(TournamentStreamService);

  tournamentId = '';
  gameId = '';
  serverUrl = '';

  fen = INITIAL_FEN;
  turn: 'white' | 'black' = 'white';
  status: GameStatus = 'pending';
  winner: 'white' | 'black' | null = null;
  clock: GameClock | null = null;
  moves: string[] = [];
  snapshot: GameStateSnapshot | null = null;

  connecting = true;
  error: string | null = null;

  ngOnInit(): void {
    this.tournamentId = this.route.snapshot.paramMap.get('id') ?? '';
    this.gameId = this.route.snapshot.paramMap.get('gameId') ?? '';
    this.serverUrl = this.route.snapshot.queryParamMap.get('server') ?? environment.tournamentServerUrl ?? '';
    if (!this.tournamentId || !this.gameId) {
      this.error = 'Missing tournament or game id.';
      this.connecting = false;
      return;
    }
    if (!this.serverUrl) {
      this.error = 'Missing tournament server URL.';
      this.connecting = false;
      return;
    }

    this.stream.streamGame(this.serverUrl, this.tournamentId, this.gameId)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: ev => this.apply(ev),
        error: err => {
          this.connecting = false;
          this.error = (err as Error).message ?? 'Stream failed.';
        }
      });
  }

  movePairs(): { n: number; white: string; black: string | null }[] {
    const pairs: { n: number; white: string; black: string | null }[] = [];
    for (let i = 0; i < this.moves.length; i += 2) {
      pairs.push({ n: i / 2 + 1, white: this.moves[i], black: this.moves[i + 1] ?? null });
    }
    return pairs;
  }

  formatTime(seconds: number | undefined): string {
    if (seconds === undefined || seconds === null) return '—';
    const s = Math.max(0, Math.floor(seconds));
    const m = Math.floor(s / 60);
    const r = s % 60;
    return `${m}:${r.toString().padStart(2, '0')}`;
  }

  statusLabel(): string {
    switch (this.status) {
      case 'pending': return 'Waiting to start';
      case 'ongoing': return `${this.turn === 'white' ? 'White' : 'Black'} to move`;
      case 'checkmate': return `Checkmate — ${this.winner ?? '—'} wins`;
      case 'stalemate': return 'Stalemate';
      case 'draw': return 'Draw';
      case 'resigned': return `Resigned — ${this.winner ?? '—'} wins`;
      case 'timeout': return `Timeout — ${this.winner ?? '—'} wins`;
    }
  }

  private apply(ev: GameStreamEvent): void {
    this.connecting = false;
    switch (ev.type) {
      case 'gameState':
        this.snapshot = ev;
        this.fen = ev.fen;
        this.turn = ev.turn;
        this.status = ev.status;
        this.winner = ev.winner;
        this.clock = ev.clock ?? null;
        this.moves = ev.moves ? ev.moves.split(/\s+/).filter(Boolean) : [];
        return;
      case 'move':
        this.fen = ev.fen;
        this.turn = ev.turn;
        if (ev.clock) this.clock = ev.clock;
        this.moves = [...this.moves, ev.uci];
        return;
      case 'gameEnd':
        this.status = ev.status;
        this.winner = ev.winner;
        return;
      case 'heartbeat':
        return;
    }
  }
}
