import {
  ReceiveLeaderboardMessage,
  SendLeaderboardMessage,
  Origin,
  ReceivePlayMessage,
  SendPlayMessage,
  SendScoreMessage,
  SendMessage,
  SendTransferHstMessage,
  ReceiveTransferHstMessage,
  ReceiveSubmitScoreMessage,
} from "./types/types.js";

export class GameService {
  private targetOrigin: string;
  private eventHandlers: Map<string, (data: any) => void>;
  private pendingPromises: Map<string, (data: any) => void>;
  private gameId: string;

  constructor(gameId: string, targetOrigin: Origin) {
    this.gameId = gameId;
    this.targetOrigin = targetOrigin;
    this.eventHandlers = new Map();
    this.pendingPromises = new Map();
  }

  // Overloaded method signatures
  public on(event: "play", handler: (data: ReceivePlayMessage) => void): void;
  public on(
    event: "leaderboard",
    handler: (data: ReceiveLeaderboardMessage) => void
  ): void;
  public on(
    event: "transferHst",
    handler: (data: ReceiveTransferHstMessage) => void
  ): void;
  public on(
    event: "score",
    handler: (data: ReceiveSubmitScoreMessage) => void
  ): void;

  // General on implementation
  public on(event: string, handler: (data: any) => void): void {
    this.eventHandlers.set(event, handler);
  }

  private sendMessage(message: SendMessage) {
    window.parent.postMessage(message, this.targetOrigin);
  }

  public init() {
    window.addEventListener("message", (event) => {
      if (
        event.origin !== this.targetOrigin &&
        !event.origin.includes("localhost")
      ) {
        throw new Error(`Invalid origin: ${event.origin}`);
      }
      const { type, data } = event.data;
      console.log(`Received message: ${type}`);
      if (this.eventHandlers.has(type)) {
        const handler = this.eventHandlers.get(type);
        if (handler) {
          handler(data);
        }
      } else if (this.pendingPromises.has(type)) {
        const resolve = this.pendingPromises.get(type);
        if (resolve) {
          resolve(data);
          this.pendingPromises.delete(type);
        }
      } else {
        console.error(`Unsupported message type: ${type}`);
      }
    });

    console.log("🕹 Haste Arcade Game Initialized!");
  }

  public async play(): Promise<ReceivePlayMessage> {
    return new Promise((resolve) => {
      this.pendingPromises.set("play", resolve);
      this.sendMessage({
        type: "play",
        gameId: this.gameId,
      } as SendPlayMessage);
    });
  }

  public async submitScore(
    playId: string,
    score: number
  ): Promise<ReceiveSubmitScoreMessage> {
    return new Promise((resolve) => {
      this.pendingPromises.set("score", resolve);
      this.sendMessage({
        type: "score",
        gameId: this.gameId,
        score,
        playId,
      } as SendScoreMessage);
    });
  }

  public async getLeaderboard(): Promise<ReceiveLeaderboardMessage> {
    return new Promise((resolve) => {
      this.pendingPromises.set("leaderboard", resolve);
      this.sendMessage({
        type: "leaderboard",
        gameId: this.gameId,
      } as SendLeaderboardMessage);
    });
  }

  public async transferHst(amount: number): Promise<ReceiveTransferHstMessage> {
    return new Promise((resolve) => {
      this.pendingPromises.set("transferHst", resolve);
      this.sendMessage({
        type: "transferHst",
        gameId: this.gameId,
        amount,
      } as SendTransferHstMessage);
    });
  }
}
