import { Component, DestroyRef, inject, OnInit } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { switchMap, of, forkJoin } from 'rxjs';

import { ChessBoardComponent } from '../../components/chess-board/chess-board.component';
import { EvalTimelineComponent } from '../../components/eval-timeline/eval-timeline.component';
import { AnnotatedMoveListComponent } from '../../components/annotated-move-list/annotated-move-list.component';

import { GameApiService } from '../../services/game-api.service';
import { AnalysisService } from '../../services/analysis.service';

import { AnnotatedMove, AnalysisResponse } from '../../models/analysis.models';
import { GameFull } from '../../models/game.models';
import { getErrorMessage } from '../../core/http/error-message.util';

const ANALYSIS_DEPTH_DEFAULT = 14;
const STARTING_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';

type InputMode = 'fen' | 'pgn' | 'game';

@Component({
  selector: 'app-analysis',
  standalone: true,
  imports: [
    RouterLink,
    FormsModule,
    ChessBoardComponent,
    EvalTimelineComponent,
    AnnotatedMoveListComponent,
  ],
  templateUrl: './analysis.component.html',
  styleUrl: './analysis.component.css',
})
export class AnalysisComponent implements OnInit {
  private readonly route = inject(ActivatedRoute);
  private readonly gameApi = inject(GameApiService);
  private readonly analysisService = inject(AnalysisService);
  private readonly destroyRef = inject(DestroyRef);

  // ── State ─────────────────────────────────────────────────
  inputMode: InputMode = 'fen';
  fenInput = '';
  pgnInput = '';
  depth = ANALYSIS_DEPTH_DEFAULT;

  loading = false;
  analysing = false;
  errorMessage = '';

  currentFen = STARTING_FEN;
  game: GameFull | null = null;

  /** FEN for each ply (index 0 = position before move 0 was played) */
  fenHistory: string[] = [STARTING_FEN];
  annotatedMoves: AnnotatedMove[] = [];
  activePly: number | null = null;

  /** Single-position analysis result (for custom FEN/PGN input) */
  positionAnalysis: AnalysisResponse | null = null;

  get displayFen(): string {
    if (this.activePly !== null && this.fenHistory[this.activePly + 1]) {
      return this.fenHistory[this.activePly + 1];
    }
    return this.currentFen;
  }

  get hasAnnotations(): boolean {
    return this.annotatedMoves.length > 0;
  }

  // ── Lifecycle ─────────────────────────────────────────────
  ngOnInit(): void {
    // Support /analysis?gameId=xxx deep-link
    this.route.queryParamMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
      const gameId = params.get('gameId');
      if (gameId) {
        this.inputMode = 'game';
        this.loadGame(gameId);
      }
    });
  }

  // ── Input mode ─────────────────────────────────────────────
  setInputMode(mode: InputMode): void {
    this.inputMode = mode;
    this.errorMessage = '';
  }

  // ── Load FEN ──────────────────────────────────────────────
  loadFen(): void {
    const fen = this.fenInput.trim();
    if (!fen) return;
    this.reset();
    this.currentFen = fen;
    this.fenHistory = [fen];
    this.analyseSinglePosition(fen);
  }

  // ── Load PGN ──────────────────────────────────────────────
  loadPgn(): void {
    const pgn = this.pgnInput.trim();
    if (!pgn) return;
    this.reset();
    this.loading = true;
    this.gameApi
      .importPgn(pgn)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (game) => {
          this.loading = false;
          this.applyGame(game);
        },
        error: (err) => {
          this.loading = false;
          this.errorMessage = getErrorMessage(err, 'Could not import PGN.');
        },
      });
  }

  // ── Load game by ID ───────────────────────────────────────
  loadGame(gameId: string): void {
    this.reset();
    this.loading = true;
    this.gameApi
      .getGame(gameId)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (game) => {
          this.loading = false;
          this.applyGame(game);
        },
        error: (err) => {
          this.loading = false;
          this.errorMessage = getErrorMessage(err, 'Could not load game.');
        },
      });
  }

  // ── Run full analysis ─────────────────────────────────────
  runAnalysis(): void {
    if (this.fenHistory.length < 2) {
      this.analyseSinglePosition(this.currentFen);
      return;
    }
    this.analysing = true;
    this.positionAnalysis = null;
    this.errorMessage = '';
    const sans =
      this.annotatedMoves.length > 0
        ? this.annotatedMoves.map((m) => m.san)
        : (this.game?.state.moves ?? []);

    this.analysisService
      .analyzeGame(sans, this.fenHistory, this.depth)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (annotated) => {
          this.annotatedMoves = annotated;
          this.analysing = false;
        },
        error: (err) => {
          this.errorMessage = getErrorMessage(err, 'Analysis failed.');
          this.analysing = false;
        },
      });
  }

  // ── Board navigation ──────────────────────────────────────
  navigateToPly(ply: number): void {
    this.activePly = ply;
  }

  navigateHistory(direction: 'first' | 'prev' | 'next' | 'last'): void {
    const total = this.fenHistory.length - 1;
    const current = this.activePly ?? total;
    let next: number;
    switch (direction) {
      case 'first':
        next = 0;
        break;
      case 'prev':
        next = Math.max(0, current - 1);
        break;
      case 'next':
        next = Math.min(total, current + 1);
        break;
      default:
        next = total;
        break;
    }
    this.activePly = next >= total ? null : next;
  }

  // ── Private helpers ───────────────────────────────────────
  private reset(): void {
    this.errorMessage = '';
    this.annotatedMoves = [];
    this.positionAnalysis = null;
    this.activePly = null;
    this.game = null;
    this.fenHistory = [STARTING_FEN];
    this.currentFen = STARTING_FEN;
  }

  private applyGame(game: GameFull): void {
    this.game = game;
    this.currentFen = game.state.fen;
    this.fenHistory = [game.state.fen];
    this.annotatedMoves = game.state.moves.map((san) => ({
      san,
      fen: game.state.fen,
      evalBefore: null,
      evalAfter: null,
      quality: null,
      bestMove: null,
      winChanceBefore: null,
      winChanceAfter: null,
    }));
    this.gameApi
      .getFenHistory(game.gameId)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (fens) => {
          if (fens.length >= 2) {
            this.fenHistory = fens;
          }
        },
      });
  }

  private analyseSinglePosition(fen: string): void {
    this.analysing = true;
    this.analysisService
      .analyzePosition(fen, this.depth)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (result) => {
          this.positionAnalysis = result;
          this.analysing = false;
        },
        error: (err) => {
          this.errorMessage = getErrorMessage(err, 'Analysis failed.');
          this.analysing = false;
        },
      });
  }
}
