# Hurry Curry! - a game about cooking
# Copyright (C) 2026 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/>.
#
class_name TileFactory
extends Object


class TileName:
	var name# : String
	var variant #: String?
	var raw_name: String
	func _init(raw_name_: String):
		raw_name = raw_name_
		var c = Array(raw_name_.split(":"))
		name = c[0]; variant = c[1] if c.size() >= 2 else null # TODO Array.get throws errors

class TileCC:
	var tile_name: TileName
	var position: Vector2i
	var neighbors: Array
	var floor_meshers: Dictionary[String, FloorMesher]
	var server_context: Game.ServerContext
	var below_tile_instances: Array[Tile]
	var above_tile_names: Array[String]

var floor_meshers: Dictionary[String, FloorMesher] = {
	"floor": FloorMesher.new(Floor.floor_mesh()),
	"path": FloorMesher.new(Path.floor_mesh()),
	"grass": GrassMesher.new(Grass.floor_mesh()),
	"street": FloorMesher.new(Street.floor_mesh())
}

const TILE_COMBINATOR: Dictionary[Array, Array] = { # : Dictionary[Array[String], Array[String]]
	["counter", "sink"]: ["sink"]
} 

func produce(parent: Node3D, tile_names: Array, position: Vector2i, neighbors: Array, server_context: Game.ServerContext = null) -> Array[Tile]:
	# Combinate tiles
	tile_names = tile_names.duplicate()
	for k in TILE_COMBINATOR:
		if G.has_all(tile_names, k):
			for item: String in k: tile_names.erase(item)
			tile_names.append_array(TILE_COMBINATOR[k])
	
	var tile_instances: Array[Tile] = []
	for i in range(tile_names.size()):
		var tile_name: String = tile_names[i]
		var above_tile_names: Array[String] = []
		above_tile_names.append_array(tile_names.slice(i+1, tile_names.size()))
		var tile := produce_part(tile_name, position, neighbors, tile_instances, above_tile_names, server_context)
		tile_instances.append(tile)
		tile.position = Vector3(position.x, 0, position.y)
		parent.add_child(tile)

	return tile_instances

func produce_part(raw_name: String, position: Vector2i, neighbors: Array, below_tile_instances: Array[Tile] = [], above_tile_names: Array[String] = [], server_context: Game.ServerContext = null) -> Tile:
	var tile_name = TileName.new(raw_name)

	var ctx := TileCC.new()
	ctx.tile_name = tile_name
	ctx.position = position
	ctx.neighbors = neighbors.map(func(a):
		if a != null:
			return a.map(func(b): return null if b == null else TileName.new(b).name)
		else: return null
	)
	ctx.floor_meshers = floor_meshers
	ctx.server_context = server_context
	ctx.below_tile_instances = below_tile_instances
	ctx.above_tile_names = above_tile_names

	match tile_name.name:
		"book": return GenericTile.new(ctx, preload("res://map/tiles/book.tscn"))
		"button": return Button_.new(ctx)
		"button-base": return ButtonBase.new(ctx)
		"ceiling-lamp": return GenericTile.new(ctx, preload("res://map/tiles/ceiling_lamp.tscn"))
		"chair": return Chair.new(ctx)
		"chandelier": return GenericTile.new(ctx, preload("res://map/tiles/chandelier.tscn"))
		"conveyor": return Conveyor.new(ctx)
		"counter-window": return CounterWindow.new(ctx)
		"counter-window-conveyor": return CounterWindowConveyor.new(ctx)
		"counter": return Counter.new(ctx)
		"cutting-board": return CuttingBoard.new(ctx)
		"door": return Door.new(ctx)
		"fence": return Fence.new(ctx)
		"floor": return Floor.new(ctx)
		"freezer": return Freezer.new(ctx)
		"grass": return Grass.new(ctx)
		"lamp": return Lamp.new(ctx)
		"map-selector": return GenericTile.new(ctx, preload("res://map/tiles/map_selector.tscn"))
		"oven": return Oven.new(ctx)
		"path": return Path.new(ctx)
		"rolling-board": return RollingBoard.new(ctx)
		"screen": return Screen.new(ctx)
		"deep-fryer": return DeepFryer.new(ctx)
		"sink": return Sink.new(ctx)
		"stove": return Stove.new(ctx)
		"street": return Street.new(ctx)
		"table": return Table.new(ctx)
		"trash": return Trash.new(ctx)
		"tree": return ExteriorTree.new(ctx)
		"wall-window": return WallWindow.new(ctx)
		"wall": return Wall.new(ctx)
		"white-hole-counter": return ItemPortal.new(ctx, 1)
		"white-hole": return PlayerPortal.new(ctx)
		"grey-hole-counter": return ItemPortal.new(ctx, 0)
		"grey-hole": return PlayerPortal.new(ctx)
		"black-hole-counter": return ItemPortal.new(ctx, -1)
		"black-hole": return PlayerPortal.new(ctx)

		"house-balcony": return HouseBalcony.new(ctx)
		"house-door": return HouseDoor.new(ctx)
		"house-oriel": return HouseOriel.new(ctx)
		"house-wall": return HouseWall.new(ctx)
		"house-side": return HouseSide.new(ctx)
		"house-roof": return HouseRoof.new(ctx)
		"house-roof-chimney": return HouseRoofChimney.new(ctx)

		"crate": return Crate.new(ctx)

		# TODO: update maps to use "crate:..."
		"bun-crate":
			ctx.tile_name.variant = "bun"
			return Crate.new(ctx)
		"cheese-crate":
			ctx.tile_name.variant = "cheese"
			return Crate.new(ctx)
		"coconut-crate":
			ctx.tile_name.variant = "coconut"
			return Crate.new(ctx)
		"fish-crate":
			ctx.tile_name.variant = "fish"
			return Crate.new(ctx)
		"flour-crate":
			ctx.tile_name.variant = "flour"
			return Crate.new(ctx)
		"leek-crate":
			ctx.tile_name.variant = "leek"
			return Crate.new(ctx)
		"lettuce-crate":
			ctx.tile_name.variant = "lettuce"
			return Crate.new(ctx)
		"mushroom-crate":
			ctx.tile_name.variant = "mushroom"
			return Crate.new(ctx)
		"noodles-crate":
			ctx.tile_name.variant = "noodles"
			return Crate.new(ctx)
		"steak-crate":
			ctx.tile_name.variant = "steak"
			return Crate.new(ctx)
		"rice-crate":
			ctx.tile_name.variant = "rice"
			return Crate.new(ctx)
		"strawberry-crate":
			ctx.tile_name.variant = "strawberry"
			return Crate.new(ctx)
		"tomato-crate":
			ctx.tile_name.variant = "tomato"
			return Crate.new(ctx)
		"potato-crate":
			ctx.tile_name.variant = "potato"
			return Crate.new(ctx)

		var t:
			push_warning("tile %s unknown" % t)
			return UnknownTile.new(ctx)
