/*
    Hurry Curry! - a game about cooking
    Copyright (C) 2025 Hurry Curry! Contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

*/
export type Vec2 = [number, number] // x, y
export type PlayerID = number // opaque number to identify players.
export type ItemIndex = number // index used primarily for item_names in Gamedata
export type TileIndex = number // index used primarily for tile_names in Gamedata
export type Hand = number

export interface MapMetadata {
    name: string,
    players: number,
    difficulty: number,
}

export interface Gamedata {
    current_map: string,
    item_names: string[], // Look-up table for ItemIndex
    tile_names: string[], // Look-up table for TileIndex
    tile_walkable: number[], // List of TileIndex that have no collision
    tile_placeable_items: { [key: string]: number[] }, // Map from TileIndex to list of ItemIndex which can be placed on that tile. Not set if not restricted
    tile_interactable_empty: number[], // List of TileIndex that have "crate recipes"
    maps: [string, MapMetadata][], // Metadata for most available maps
    bot_algos: string[],
    hand_count: number,
}

export type PacketS =
    { type: "join", name: string, character: Character, class: PlayerClass } // Spawns a new character. The server replies with "joined". Dont send it to spectate.
    | { type: "leave", player: PlayerID } // Despawns a character
    | { type: "idle", paused: boolean } // Indicates that this player is actively participating in the game right now.
    | { type: "movement", player: PlayerID, pos: Vec2, dir: Vec2, boost: boolean }
    | { type: "interact", player: PlayerID, pos?: Vec2, hand: number } // Interact with some tile. pos is a position when pressing and null when releasing interact button
    | { type: "communicate", player: PlayerID, message?: Message, timeout?: number, pin?: boolean } // Sends a message
    | { type: "effect", player: PlayerID, name: string } // Sends an effect
    | { type: "replay_tick", dt: number } // Steps forward in replay.
    | { type: "ready" }

export type PacketC =
    { type: "version", minor: number, major: number, supports_bincode?: boolean } // Sent once after connecting to ensure you client is compatible
    | { type: "joined", id: PlayerID } // Informs you about the id of the character you spawned
    | { type: "data", data: Gamedata } // Game data was changed
    | { type: "add_player", id: PlayerID, name: string, position: Vec2, character: Character, class: PlayerClass } // Somebody else joined (or was already in the game)
    | { type: "remove_player", id: PlayerID }  // Somebody left
    | { type: "movement", player: PlayerID, pos: Vec2, rot: number, boost: boolean, dir: Vec2 } // Update the movement of a players (your own position is included here)
    | { type: "movement_sync", player: PlayerID } // Your movement is difference on the server, you should update your position from a `position` packet
    | { type: "move_item", from: ItemLocation, to: ItemLocation } // Item moved
    | { type: "set_item", location: ItemLocation, item?: ItemIndex } // the item contained in a tile or player changed
    | { type: "set_progress", item: ItemLocation, position: number, speed: number, warn: boolean, player?: PlayerID } // A tile is doing something. position goes from 0 to 1, speed unit is in 1 per second
    | { type: "clear_progress", item: ItemLocation }
    | { type: "update_map", tile: Vec2, kind: TileIndex | null, neighbors: (TileIndex | null)[] } // A map tile was changed
    | { type: "flush_map" }
    | { type: "communicate", player: PlayerID, message?: Message, timeout?: MessageTimeout } // A player wants to communicate something, message is null when cleared
    | { type: "effect", player: PlayerID, name: string } // Player sent an effect
    | { type: "server_message", message: Message, error: boolean } // Text message from the server
    | { type: "server_hint", message?: Message, position?: Vec2, player: PlayerID } // Hint message from server with optional position. Message is unset to clear previous message
    | { type: "score" } & Score // Supplies information for score OSD
    | { type: "menu" } & Menu // Open a menu on the client-side
    | { type: "environment", effects: string[] }
    | { type: "tutorial_ended", item: ItemIndex, player: PlayerID, success: boolean }
    | { type: "set_ingame", state: boolean, lobby: boolean } // Set to false when entering the game or switching maps
    | { type: "pause", state: boolean } // Set game paused so clients dont increment timers

export interface Character {
    color: number,
    headwear: number,
    hairstyle: number
}

export type Menu =
    { menu: "score", data: Score }
    | { menu: "scoreboard", data: Scoreboard }
    | { menu: "book", data: Book }
    | { menu: "announce_start" }

export interface MessageTimeout {
    initial: number,
    remaining: number,
    pinned: boolean,
}

export interface Scoreboard {
    map: string,
    plays: number,
    best: ScoreboardEntry
}
export interface ScoreboardEntry {
    players: string[],
    score: Score
}

export interface Score {
    points: number,
    demands_failed: number,
    demands_completed: number,
    time_remaining: number,
    players: number,
    active_recipes: number,
    passive_recipes: number,
    instant_recipes: number,
    stars: number,
}

export type Message =
    { item: number }
    | { tile: number }
    | { text: string }
    | { translation: { id: string, params: Message[] } }

export type ItemLocation =
    { player: [PlayerID, Hand] }
    | { tile: Vec2 }

export type PlayerClass = "chef" | "bot" | "customer" | "tram"

export interface Book { pages: BookPage[] }
export type BookPage =
    { page_type: "cover" }
    | { page_type: "contents", title: Message, table: [Message, number][] }
    | { page_type: "text", title: Message, paragraphs: Message[] }
    | { page_type: "recipe", title: Message, description: Message, diagram: Diagram }

export interface Diagram {
    nodes: DiagramNode[]
    edges: DiagramEdge[]
}
export interface DiagramNode {
    position: Vec2,
    label: Message,
    style: NodeStyle
}
export interface DiagramEdge {
    src: number,
    dst: number,
}
export type NodeStyle =
    "intermediate_product"
    | "final_product"
    | "process_active"
    | "process_passive"
    | "process_instant"
