import { writable } from "svelte/store";

import { createBuilding, createHero, createQuest } from "./create";
import worldmap from "./data/worldmap";
import { getTilesAtDistance, Hex } from "./hexgrid";
import { WORLDMAP_TYPES, type BuildingType, type CostType, type HeroType, type QuestType, type RegionType, type ResourcesType } from "./types";
import { distanceBetweenCells, getAdjacentWorldmapCells, getKeysAsNumbers, indexToPoint, shuffle } from "./utils";
import { WORLD_MAP_HEIGHT, WORLD_MAP_WIDTH } from "./constants";


type Board = {
    [key: number]: {
        [key: number]: number;
    }
}


export interface VillageState {
    buildings: BuildingType[];
    units: {
        [key: string]: number;
    },
    resources: ResourcesType;
    villageTiles: Board;
    outsideTiles: Board;
    worldmap: RegionType[];
    heroes: HeroType[];
    quests: QuestType[];
    victory: boolean;
}


export const DEFAULT_TILE = -1;
export const VILLAGE_TILE = -2;


function getInitialVillageBoard() {
    const board: Board = {
        0: { 0: DEFAULT_TILE },
    };
    for (let i = 1; i <= 2; i++) {
        getTilesAtDistance(i).forEach(tile => {
            if (board[tile.y] === undefined) {
                board[tile.y] = {};
            }

            board[tile.y][tile.x] = DEFAULT_TILE;
        });
    }
    return board;
}


function getInitialOutsideBoard() {
    const board: Board = {
        0: { 0: VILLAGE_TILE },
    };
    for (let i = 1; i <= 2; i++) {
        getTilesAtDistance(i).forEach(tile => {
            if (board[tile.y] === undefined) {
                board[tile.y] = {};
            }

            board[tile.y][tile.x] = DEFAULT_TILE;
        });
    }
    return board;
}


function getInitialWorldmap(): RegionType[] {
    const board: RegionType[] = [];
    const centerIndex = Math.floor((WORLD_MAP_WIDTH * WORLD_MAP_HEIGHT) / 2);
    const centerPoint = indexToPoint(centerIndex);

    for (let i = 0; i < WORLD_MAP_WIDTH * WORLD_MAP_HEIGHT; i++) {
        board[i] = {
            id: i,
            type: WORLDMAP_TYPES.EMPTY,
            distance: distanceBetweenCells(indexToPoint(i), centerPoint),
        };
    }
    board[centerIndex].type = WORLDMAP_TYPES.BOURGADE;

    worldmap.forEach(region => {
        const candidates = board.filter(c =>
                c.type === WORLDMAP_TYPES.EMPTY
                && c.distance >= region.distance[0]
                && c.distance < region.distance[1]
        );
        const cell = shuffle(candidates)[0];
        board[cell.id] = {
            type: WORLDMAP_TYPES.OASIS,
            id: cell.id,
            resource: region.resource as keyof CostType,
            distance: cell.distance,
            strength: Math.round(cell.distance * cell.distance * 50),
            state: {
                cleared: false,
            },
        };
    });

    return board;
}


function getInitialQuests(): QuestType[] {
    return [
        createQuest(1),
        createQuest(1),
        createQuest(1),
    ];
}


function getInitialState() {
    const state: VillageState = {
        buildings: [],
        units: {},
        resources: {
            wood: 60,
            stone: 60,
            iron: 60,
            food: 50,
            culture: 0,
        },
        villageTiles: getInitialVillageBoard(),
        outsideTiles: getInitialOutsideBoard(),
        worldmap: getInitialWorldmap(),
        heroes: [
            createHero(),
        ],
        quests: getInitialQuests(),
        victory: false,
    };

    // Create the Town hall.
    const townhall = createBuilding('townhall');
    // townhall.level = 20;
    state.villageTiles[0][0] = townhall.id;
    state.buildings.push(townhall);

    // Create all the resource buildings.
    const resourceBuildingTypes = shuffle([
        'woodcutter', 'woodcutter', 'woodcutter', 'woodcutter',
        'mine', 'mine', 'mine', 'mine',
        'pit', 'pit', 'pit', 'pit',
        'field', 'field', 'field', 'field', 'field', 'field',
    ]);
    getKeysAsNumbers(state.outsideTiles).forEach(y => {
        getKeysAsNumbers(state.outsideTiles[y]).forEach(x => {
            if (state.outsideTiles[y][x] !== DEFAULT_TILE) {
                return;
            }

            const type = resourceBuildingTypes.pop();
            if (type === undefined) {
                throw new Error("Not enough building types for outside resource buildings");
            }
            const newBuilding = createBuilding(type);
            newBuilding.tile = new Hex(x, y);
            newBuilding.level = 1; //20; //newBuilding.type === 'field' ? 1 : 10;
            state.outsideTiles[y][x] = newBuilding.id;
            state.buildings.push(newBuilding);
        });
    });

    return state;
}


const village = writable<VillageState>(getInitialState());


function reset() {
    village.set(getInitialState());
}


export default {
    ...village,
    reset,
};
