/*
    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/>.

*/

type Component = (ctx: CanvasRenderingContext2D) => void
function base(fill: string, stroke?: string, stroke_width?: number): Component {
    return c => {
        c.fillStyle = fill;
        c.strokeStyle = stroke ?? "black";
        c.lineWidth = stroke_width ?? 0.05
        c.lineJoin = "miter"
        c.lineCap = "square"
        c.fillRect(
            -0.5,
            -0.5,
            1,
            1
        )
        if (stroke) c.strokeRect(
            -0.5 + c.lineWidth / 2,
            -0.5 + c.lineWidth / 2,
            1 - c.lineWidth,
            1 - c.lineWidth
        )
    }
}
function rect(inset: number, fill: string, stroke?: string, stroke_width?: number): Component {
    return c => {
        c.fillStyle = fill;
        c.strokeStyle = stroke ?? "black";
        c.lineWidth = stroke_width ?? 0.05
        c.lineJoin = "round"
        c.lineCap = "round"
        c.fillRect(
            -0.5 + inset,
            -0.5 + inset,
            1 - inset * 2,
            1 - inset * 2
        )
        if (stroke) c.strokeRect(
            -0.5 + inset,
            -0.5 + inset,
            1 - inset * 2,
            1 - inset * 2
        )
    }
}
function circle(radius: number, fill: string, stroke?: string, stroke_width?: number): Component {
    return c => {
        c.fillStyle = fill;
        c.strokeStyle = stroke ?? "black";
        c.lineWidth = stroke_width ?? 0.05
        c.beginPath()
        c.arc(0.0, 0.0, radius, 0, Math.PI * 2)
        if (stroke) c.stroke()
        c.fill()
    }
}
function cross(size: number, stroke: string, stroke_width = 0.05): Component {
    return c => {
        c.strokeStyle = stroke
        c.lineWidth = stroke_width
        c.lineCap = "round"
        c.beginPath()
        c.moveTo(-size, -size)
        c.lineTo(size, size)
        c.moveTo(size, -size)
        c.lineTo(-size, size)
        c.stroke()
    }
}
function text(s: string): Component {
    return c => {
        c.font = "0.8px sans-serif"
        c.strokeStyle = "#e38242"
        c.fillStyle = "white"
        c.lineWidth = 0.05
        c.textAlign = "center"
        c.textBaseline = "middle"
        c.lineJoin = "round"
        c.lineCap = "round"
        c.strokeText(s, 0, 0)
        c.fillText(s, 0, 0)
    }
}

function arrange_items(...items: ItemName[]): Component {
    return c => {
        for (let index = 0; index < items.length; index++) {
            const item = items[index];

            const t = index / items.length * Math.PI * 2.
            const radius = items.length == 1 ? 0 : (0.4 / items.length)
            const off_x = Math.sin(t) * radius
            const off_y = Math.cos(t) * radius
            const scale = 1. / Math.sqrt(items.length)

            c.save()
            c.translate(off_x, off_y)
            c.scale(scale, scale)
            iref(item)(c)
            c.restore()
        }
    }
}

const door: Component = c => {
    c.fillStyle = "#ff9843"
    c.fillRect(-0.5, -0.1, 1, 0.2)
}

const iref = (name: ItemName): Component => c => draw_item_sprite(c, name)
const tref = (name: TileName): Component => c => TILES[name].forEach(f => f(c))

export type ItemName = string
export type TileName = "sink" | "conveyor" | "book" | "lettuce-crate" | "cheese-crate" | "tomato-crate" | "steak-crate" | "flour-crate" | "leek-crate" | "rice-crate" | "fish-crate" | "coconut-crate" | "strawberry-crate" | "oven" | "cutting-board" | "stove" | "freezer" | "trash" | "grass" | "tree" | "wall" | "chair" | "floor" | "door" | "counter" | "wall-window" | "table" | "counter-window" | "path" | "lamp" | "street"

const ITEMS: { [key in ItemName]: (c: string[]) => Component } = {
    "bun": () => circle(0.3, "#853e20"),
    "burned": () => c => (circle(0.3, "rgb(61, 18, 0)")(c), cross(0.2, "red", 0.02)(c)),
    "coconut": () => circle(0.3, "rgb(75, 49, 25)"),
    "cooked-rice": () => circle(0.3, "rgb(233, 233, 233)"),
    "curry": () => circle(0.3, "rgb(185, 67, 37)"),
    "dough": () => circle(0.3, "#b38d7d"),
    "fish": () => circle(0.3, "rgb(62, 66, 104)"),
    "flour": () => circle(0.3, "#d8c9c2"),
    "leek": () => circle(0.3, "rgb(50, 133, 17)"),
    "milk": () => circle(0.3, "rgb(252, 243, 208)"),
    "nigiri": () => circle(0.25, "rgb(233, 233, 233)", "salmon"),
    "rice": () => circle(0.3, "rgb(163, 163, 163)"),
    "seared-steak": () => circle(0.3, "#702200"),
    "sliced-bun": () => circle(0.3, "#853e20"),
    "sliced-fish": () => circle(0.3, "salmon", "rgb(62, 66, 104)"),
    "steak": () => circle(0.3, "#ca3510"),
    "patty": () => circle(0.3, "#c26149"),
    "seared-patty": () => circle(0.3, "#502c23"),
    "strawberry-icecream": () => circle(0.2, "rgb(250, 148, 236)"),
    "strawberry-mochi": () => circle(0.2, "rgb(161, 111, 132)"),
    "strawberry-shake": () => circle(0.3, "rgb(255, 180, 180)"),
    "strawberry": () => circle(0.3, "rgb(228, 79, 111)"),
    "tomato-juice": () => circle(0.3, "#b80000"),
    "tomato-soup": () => circle(0.3, "#ff2600"),
    "water": () => circle(0.3, "rgb(86, 92, 206)"),
    "tomato": () => circle(0.3, "#d63838"),
    "sliced-tomato": () => circle(0.3, "#d16363", "#d63838", 0.08),
    "lettuce": () => circle(0.3, "#64a30b"),
    "sliced-lettuce": () => circle(0.3, "#a0da4f", "#64a30b", 0.08),
    "cheese": () => circle(0.3, "#b3b615"),
    "sliced-cheese": () => rect(0.25, "#dcdf29", "#b3b615", 0.05),
    "dirty-plate": () => circle(0.4, "#947a6f", "#d3a187", 0.02),
    "mochi-dough": () => circle(0.3, "rgb(172, 162, 151)"),
    "rice-flour": () => iref("rice"),
    "unknown-order": () => text("!"),

    "pan": i => c => (circle(0.35, "rgb(29, 29, 29)", "rgb(39, 39, 39)", 0.04)(c), arrange_items(...i)(c)),
    "pot": i => c => (circle(0.27, "rgb(29, 29, 29)", "rgb(56, 56, 56)", 0.2)(c), arrange_items(...i)(c)),
    "foodprocessor": i => c => (circle(0.35, "rgb(86, 168, 189)", "rgb(88, 222, 255)", 0.04)(c), arrange_items(...i)(c)),
    "plate": i => c => (circle(0.4, "#b6b6b6", "#f7f7f7", 0.02)(c), arrange_items(...i)(c)),
    "glass": i => c => (circle(0.35, "rgb(150, 255, 237)", "rgb(52, 129, 155)", 0.02), arrange_items(...i)(c)),

}

const crate = (i: ItemName) => [base("#60701e", "#b9da37", 0.05), iref(i)];
const floor = tref("floor");
const counter = tref("counter");
const TILES: { [key in TileName]: Component[] } = {
    "floor": [base("#333", "#222", 0.05)],
    "street": [base("rgb(19, 19, 19)")],
    "table": [base("rgb(133, 76, 38)")],
    "door": [floor, door],
    "chair": [floor, circle(0.45, "rgb(136, 83, 41)")],
    "wall": [base("rgb(0, 14, 56)")],
    "wall-window": [base("rgb(19, 40, 102)")],
    "counter": [base("rgb(182, 172, 164)")],
    "counter-window": [base("rgb(233, 233, 233)")],
    "grass": [base("rgb(0, 107, 4)")],
    "path": [base("rgb(100, 80, 55)")],
    "conveyor": [base("rgb(107, 62, 128)")],
    "tree": [base("rgb(1, 82, 4)")],
    "cutting-board": [counter, rect(0.3, "rgb(158, 236, 68)", "rgb(158, 236, 68)", 0.2)],
    "trash": [floor, circle(0.4, "rgb(20, 20, 20)"), cross(0.3, "rgb(90, 36, 36)")],
    "sink": [base("rgb(131, 129, 161)", "rgb(177, 174, 226)", 0.2)],
    "oven": [base("rgb(241, 97, 61)", "rgb(109, 84, 84)", 0.3)],
    "freezer": [base("rgb(61, 97, 241)", "rgb(84, 88, 109)", 0.3)],
    "stove": [counter, circle(0.4, "#444", "#999")],
    "book": [counter, rect(0.2, "rgb(88, 44, 7)")],
    "lamp": [tref("grass"), rect(0.3, "rgb(255, 217, 127)", "rgb(32, 32, 32)", 0.1)],

    "flour-crate": crate("flour"),
    "steak-crate": crate("steak"),
    "tomato-crate": crate("tomato"),
    "lettuce-crate": crate("lettuce"),
    "cheese-crate": crate("cheese"),
    "leek-crate": crate("leek"),
    "rice-crate": crate("rice"),
    "fish-crate": crate("fish"),
    "coconut-crate": crate("coconut"),
    "strawberry-crate": crate("strawberry"),
}

function debug_label(ctx: CanvasRenderingContext2D, name: string) {
    ctx.save()
    ctx.font = "10px sans-serif"
    ctx.fillStyle = "white"
    ctx.strokeStyle = "black"
    ctx.lineWidth = 1
    ctx.textAlign = "center"
    ctx.textBaseline = "middle"
    ctx.scale(0.03, 0.03)
    ctx.strokeText(name, 0, 0)
    ctx.fillText(name, 0, 0)
    ctx.restore()
}

// TODO performance
export function draw_item_sprite(ctx: CanvasRenderingContext2D, name: ItemName) {
    const [base, cont] = name.split(":")
    const c = ITEMS[base]
    if (c) {
        c(cont?.split(",") ?? [])(ctx)
    } else {
        circle(0.4, "#f0f")(ctx)
        debug_label(ctx, name)
    }
}
export function draw_tile_sprite(ctx: CanvasRenderingContext2D, name: TileName) {
    const comps = TILES[name]
    if (comps) {
        for (const c of comps) {
            c(ctx)
        }
    } else {
        base("#f0f")(ctx)
        debug_label(ctx, name)
    }

}
