package gamemap

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"lab.zaar.be/thefish/alchemyst-go/engine/items"
	"lab.zaar.be/thefish/alchemyst-go/engine/mob"
	"lab.zaar.be/thefish/alchemyst-go/engine/types"
	"lab.zaar.be/thefish/alchemyst-go/util/appctx"
)

type PrefabFile struct {
	DefaultTileLegend map[string]string `json:"default_tile_legend"`
	DefaultMobsLegend map[string]string `json:"default_mobs_legend"`
	DefaultItemLegend map[string]string `json:"default_item_legend"`
	Prefabs           []PrefabRecord
}

type PrefabRecord struct {
	name string
	Size struct {
		X int `json:"x"`
		Y int `json:"y"`
	} `json:"Size"`
	TileLegend map[string]string `json:"tile_legend"`
	MobsLegend map[string]string `json:"mobs_legend"`
	ItemLegend map[string]string `json:"item_legend"`
	Body       []string          `json:"body"`
}

func LoadPrefabFile(filename string) (*PrefabFile, error) {
	data, err := ioutil.ReadFile(filename)
	if err!= nil {
		return nil, err
	}
	instance := &PrefabFile{}
	err = json.Unmarshal(data, instance)
	if err != nil {
		return nil, err
	}
	return instance, nil
}

type PrefabLoader struct {
	ctx context.Context
}

func NewPrefabLoader(ctx context.Context) PrefabLoader {
	return PrefabLoader{ctx: ctx}
}

func (pfbl PrefabLoader) PrefabRoomsList() []Room {

	rooms := make([]Room, 0)
	file, err := LoadPrefabFile("./assets/prefabs/test.json")
	if err !=nil {
		panic(err)
	}

	//prepare actual legends
	currentTileLegend := file.DefaultTileLegend
	currentMobsLegend := file.DefaultMobsLegend
	currentItemLegend := file.DefaultItemLegend

	for _, rawPrefab := range file.Prefabs {

		for k,v := range rawPrefab.TileLegend {
			currentTileLegend[k] = v
		}
		for k,v := range rawPrefab.MobsLegend {
			currentMobsLegend[k] = v
		}
		for k,v := range rawPrefab.ItemLegend {
			currentItemLegend[k] = v
		}

		room := Room{
			Rect:types.Rect{0, 0, rawPrefab.Size.X, rawPrefab.Size.Y},
			Center: types.Coords{rawPrefab.Size.X / 2, rawPrefab.Size.Y / 2}, //fixme
			Geometry: make([]func()*Tile, rawPrefab.Size.X*rawPrefab.Size.Y),
			Mobs: make([]mob.Mob, rawPrefab.Size.X*rawPrefab.Size.Y),
			Items: make([]items.Carried, rawPrefab.Size.X*rawPrefab.Size.Y),
 			Connectors: make([]types.Coords, 0),
		}
		//make geometry
		var f func() *Tile

		for j := 0; j < room.H; j++ {
			str := rawPrefab.Body[j]
			if len(str) != room.W {
				continue;
			}
			for i:=0; i < room.W; i++ {
				ok := false
				shortName := currentTileLegend[string(str[i])]
				if shortName == "" {
					continue
				}
				if shortName == "any" {
					continue
				}
				if shortName == "connector" {
					f = NewWall
					room.Connectors = append(room.Connectors, types.Coords{i,j})
				} else {
					f, ok = TileTypeMap[shortName]
					if (!ok) {
						appctx.Logger(pfbl.ctx).Warn().Msgf("Unknown tile: %s", shortName)
					}
				}
				room.Geometry[i+ j*room.W] = f
			}
		}
		//add room to list
		rooms = append(rooms, room)
	}
	return rooms
}

var TileTypeMap = map[string]func()*Tile{
	"wall": NewWall,
	"floor": NewFloor,
	"decorated_wall": NewDecoratedWall,
	"water": NewWaterTile,
	"deep_water": NewDeepWaterTile,
}