import { Room, type Client } from "@colyseus/core";
import { LobbyState, Player, WorldObject } from "./schema/LobbyState.ts";

interface MoveMessage {
  x: number;
  y: number;
  z: number;
  rot: number;
  anim: string;
}

interface InteractMessage {
  objectId: string;
  action?: string;
}

interface RenameMessage {
  name: string;
}

export class LobbyRoom extends Room<{ state: typeof LobbyState }> {
  state = new LobbyState();
  maxClients = 100;
  private visitorCounter = 0;

  messages = {
    move: (client: Client, message: MoveMessage) => {
      const player = this.state.players.get(client.sessionId);
      if (!player) return;

      player.x = message.x;
      player.y = message.y;
      player.z = message.z;
      player.rot = message.rot;
      player.anim = message.anim;
    },

    rename: (client: Client, message: RenameMessage) => {
      const player = this.state.players.get(client.sessionId);
      if (!player) return;

      const name = (message.name || "").trim().slice(0, 16);
      if (name.length < 1) return;

      player.displayName = name;
    },

    interact: (client: Client, message: InteractMessage) => {
      this.handleInteract(client, message);
    },

    release: (client: Client, message: { objectId: string }) => {
      const obj = this.state.objects.get(message.objectId);
      if (!obj) return;
      if (obj.usedBy !== client.sessionId) return;

      obj.state = "default";
      obj.usedBy = "";
    },
  };

  onCreate(options: any) {
    this.setSimulationInterval((dt) => this.update(dt), 1000 / 20);
    this.registerWorldObjects();
  }

  onJoin(client: Client, options: any) {
    this.visitorCounter++;

    const player = new Player();
    player.x = (Math.random() - 0.5) * 8;
    player.y = 0;
    player.z = (Math.random() - 0.5) * 8;
    player.rot = 0;
    player.anim = "idle";
    player.displayName = options.displayName || `Visitor${String(this.visitorCounter).padStart(4, "0")}`;
    player.skinIndex = Math.floor(Math.random() * 5);

    this.state.players.set(client.sessionId, player);
    console.log(`[Lobby] ${player.displayName} joined (${this.state.players.size} online)`);
  }

  async onLeave(client: Client, code: number) {
    const player = this.state.players.get(client.sessionId);
    if (player) {
      console.log(`[Lobby] ${player.displayName} left (code: ${code})`);
    }

    // Release any objects held by this player
    this.state.objects.forEach((obj) => {
      if (obj.usedBy === client.sessionId) {
        obj.state = "default";
        obj.usedBy = "";
      }
    });

    this.state.players.delete(client.sessionId);
  }

  update(dt: number) {
    // Future: NPC patrol, timed events, etc.
  }

  private handleInteract(client: Client, message: InteractMessage) {
    const obj = this.state.objects.get(message.objectId);
    if (!obj) return;

    const player = this.state.players.get(client.sessionId);
    if (!player) return;

    // Distance check (obj.data stores "posX,posZ")
    const parts = obj.data.split(",");
    const objX = parseFloat(parts[0] || "0");
    const objZ = parseFloat(parts[1] || "0");
    const dx = player.x - objX;
    const dz = player.z - objZ;
    const dist = Math.sqrt(dx * dx + dz * dz);
    if (dist > 4.0) return;

    switch (obj.objectType) {
      case "arcade_cabinet":
        if (obj.state === "default") {
          obj.state = "in_use";
          obj.usedBy = client.sessionId;
          this.broadcast("object_used", {
            objectId: obj.objectId,
            by: player.displayName,
          });
        }
        break;

      case "door":
        obj.state = obj.state === "open" ? "closed" : "open";
        break;

      case "toggle":
        obj.state = obj.state === "on" ? "off" : "on";
        break;

      case "pickup":
        if (obj.state === "available") {
          obj.state = "collected";
          obj.usedBy = client.sessionId;
        }
        break;

      default:
        obj.state = message.action || "activated";
        obj.usedBy = client.sessionId;
        break;
    }
  }

  private registerWorldObjects() {
    const definitions = [
      { id: "cabinet_01", type: "arcade_cabinet", pos: "5,0" },
      { id: "cabinet_02", type: "arcade_cabinet", pos: "-5,0" },
      { id: "cabinet_03", type: "arcade_cabinet", pos: "0,5" },
      { id: "door_main", type: "door", pos: "0,-8" },
    ];

    for (const def of definitions) {
      const obj = new WorldObject();
      obj.objectId = def.id;
      obj.objectType = def.type;
      obj.state = def.type === "door" ? "closed" : "default";
      obj.data = def.pos;
      obj.usedBy = "";
      this.state.objects.set(def.id, obj);
    }
  }
}
