import type { FieldSize } from '@/scripts/interfaces/FieldSize';
import * as signalR from '@microsoft/signalr';

export interface GameInformationDto {
  id: string | null;
  players: Player[];
  state: number;
  currentField: number[][];
  currentTurn: number;
}

export interface Player {
  name: string;
  connectionId: string;
  playerTag: number;
}

export interface GameEndedDto {
  method: string,
  player?: Player | null;
}

export interface GameIdentifier{
  gameId: string;
  gameCode: number;
}

class GameConnection {
  private connection: signalR.HubConnection;
  public playerName: string;

  public onGameCreated?: (gameIdentifier: GameIdentifier) => void;
  public onGameJoined?: (gameIdentifier: GameIdentifier) => void;
  public onGameStarted?: (gameInfo: GameInformationDto) => void;
  public onGameInformation?: (gameInfo: GameInformationDto) => void;
  public onFieldUpdated?: (currentField: GameInformationDto) => void;
  public onGameEnded?: (gameEndedInfo: GameEndedDto) => void;
  public onError?: (error: string) => void;
  public onGameDestroyed?: () => void;

  constructor(playerName: string) {
    this.playerName = playerName;
    this.connection = new signalR.HubConnectionBuilder()
      .withUrl('/api/gamehub')
      .withAutomaticReconnect()
      .build();
    
    this.connection.on('GameCreated', (payload: GameIdentifier) => {
      this.onGameCreated?.(payload);
    });

    this.connection.on('GameJoined', (payload: GameIdentifier) => {
      this.onGameJoined?.(payload);
    });

    this.connection.on('GameStarted', (payload: GameInformationDto) => {
      this.onGameStarted?.(payload);
    });

    this.connection.on('GameInformation', (payload: GameInformationDto) => {
      this.onGameInformation?.(payload);
    });

    this.connection.on('FieldUpdated', (payload: GameInformationDto) => {
      this.onFieldUpdated?.(payload);
    });

    this.connection.on('GameEnded', (payload: GameEndedDto) => {
      this.onGameEnded?.(payload);
    });

    this.connection.on('Error', (error: string) => {
      this.onError?.(error);
    });

    this.connection.on('GameDestroyed', () => {
      this.onGameDestroyed?.();
    });
  }

  async connect() {
    await this.connection.start();
    console.log('Connected');
  }

  async createGame(gFs: FieldSize) {
    await this.connection.invoke('CreateGame', this.playerName, gFs);
  }

  async joinGame(gameCode: number) {
    await this.connection.invoke('JoinGame', this.playerName, gameCode);
  }

  async requestGameInformation(gameId: string) {
    await this.connection.invoke('RequestGameInformation', gameId);
  }

  async drop(gameId: string, column: number){
    await this.connection.invoke('Drop', gameId, column);
  }
}

export default GameConnection;
