import { createHero } from "../create";
import type { BuildingType } from "../types";
import { getEmptyResources } from "../utils";
import type { VillageState } from "../village";


function getStandardTimeToBuild(level: number) {
    return Math.round(Math.pow(level, 1 / 0.8) + 2);
}


function getResourceBuildingCost(level: number, initial: number) {
    return initial * level * (level - 1);
}


function getStorageBuildingCost(level: number, initial: number) {
    return initial * Math.round( (level + level * level) / 3);
}


function getUnitBuildingCost(level: number, initial: number) {
    return initial * Math.round( (level + level * level) / 2);
}


function getMultiplierBuildingCost(level: number, initial: number) {
    return initial * Math.round( (level + level * level) / 3);
}


export default [
    {
        type: 'townhall',
        name: 'Town Hall',
        autoBuilt: true,
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getResourceBuildingCost(level, 10),
                stone: getResourceBuildingCost(level, 15),
                iron: getResourceBuildingCost(level, 20),
                food: getResourceBuildingCost(level, 5),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            storage: (_V: VillageState, _self: BuildingType) => {
                return {
                    'wood': 100,
                    'stone': 100,
                    'iron': 100,
                    'food': 100,
                }
            },
            constructionTimeReductionPerLevel: 0.025,
        },
    },
    {
        type: 'woodcutter',
        name: 'Woodcutter',
        autoBuilt: true,
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getResourceBuildingCost(level, 6),
                stone: getResourceBuildingCost(level, 10),
                iron: getResourceBuildingCost(level, 14),
                food: getResourceBuildingCost(level, 10),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const outputPerMinute = 5 * (self.level * self.level);
                prod.wood = outputPerMinute;

                const intakePerMinute = Math.ceil(self.level / 5);
                prod.food = -intakePerMinute;

                return prod;
            },
        },
    },
    {
        type: 'mine',
        name: 'Mine',
        autoBuilt: true,
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getResourceBuildingCost(level, 10),
                stone: getResourceBuildingCost(level, 14),
                iron: getResourceBuildingCost(level, 6),
                food: getResourceBuildingCost(level, 10),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const outputPerMinute = 5 * (self.level * self.level);
                prod.iron = outputPerMinute;

                const intakePerMinute = Math.ceil(self.level / 5);
                prod.food = -intakePerMinute;

                return prod;
            },
        },
    },
    {
        type: 'pit',
        name: 'Pit',
        autoBuilt: true,
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getResourceBuildingCost(level, 14),
                stone: getResourceBuildingCost(level, 6),
                iron: getResourceBuildingCost(level, 10),
                food: getResourceBuildingCost(level, 10),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const outputPerMinute = 5 * (self.level * self.level);
                prod.stone = outputPerMinute;

                const intakePerMinute = Math.ceil(self.level / 5);
                prod.food = -intakePerMinute;

                return prod;
            },
        },
    },
    {
        type: 'field',
        name: 'Field',
        autoBuilt: true,
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getResourceBuildingCost(level, 14),
                stone: getResourceBuildingCost(level, 14),
                iron: getResourceBuildingCost(level, 12),
                food: getResourceBuildingCost(level, 0),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const outputPerMinute = 5 * (self.level * self.level);
                prod.food = outputPerMinute;
                return prod;
            },
        },
    },
    {
        type: 'warehouse',
        name: 'Warehouse',
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getStorageBuildingCost(level, 15),
                stone: getStorageBuildingCost(level, 20),
                iron: getStorageBuildingCost(level, 10),
                food: getStorageBuildingCost(level, 15),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            storage: (V: VillageState, self: BuildingType) => {
                const x = self.level;
                const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 25;
                return {
                    'wood': capacity,
                    'stone': capacity,
                    'iron': capacity,
                    'food': 0,
                };
            },
        },
    },
    {
        type: 'granary',
        name: 'Granary',
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getStorageBuildingCost(level, 12),
                stone: getStorageBuildingCost(level, 22),
                iron: getStorageBuildingCost(level, 10),
                food:getStorageBuildingCost(level,  6),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            storage: (V: VillageState, self: BuildingType) => {
                const x = self.level;
                const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 25;
                return {
                    'wood': 0,
                    'stone': 0,
                    'iron': 0,
                    'food': capacity,
                };
            },
        },
    },
    {
        type: 'great-warehouse',
        name: 'Great Warehouse',
        maxLevel: 20,
        requiredTownhallLevel: 15,
        cost: (level: number) => {
            return {
                wood: getStorageBuildingCost(level, 150),
                stone: getStorageBuildingCost(level, 200),
                iron: getStorageBuildingCost(level, 100),
                food: getStorageBuildingCost(level, 150),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 2,
        behavior: {
            storage: (V: VillageState, self: BuildingType) => {
                const x = self.level;
                const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 250;
                return {
                    'wood': capacity,
                    'stone': capacity,
                    'iron': capacity,
                    'food': 0,
                };
            },
        },
    },
    {
        type: 'great-granary',
        name: 'Great Granary',
        maxLevel: 20,
        requiredTownhallLevel: 15,
        cost: (level: number) => {
            return {
                wood: getStorageBuildingCost(level, 120),
                stone: getStorageBuildingCost(level, 220),
                iron: getStorageBuildingCost(level, 100),
                food:getStorageBuildingCost(level,  60),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 2,
        behavior: {
            storage: (V: VillageState, self: BuildingType) => {
                const x = self.level;
                const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 250;
                return {
                    'wood': 0,
                    'stone': 0,
                    'iron': 0,
                    'food': capacity,
                };
            },
        },
    },
    {
        type: 'university',
        name: 'University',
        maxLevel: 20,
        requiredTownhallLevel: 3,
        cost: (level: number) => {
            return {
                wood: getUnitBuildingCost(level, 75),
                stone: getUnitBuildingCost(level, 90),
                iron: getUnitBuildingCost(level, 50),
                food: getUnitBuildingCost(level, 45),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const intakePerMinute = self.level * 2;
                prod.food = -intakePerMinute;
                return prod;
            },
            units: {
                type: 'philosopher',
                recruitmentTime: (V: VillageState, self: BuildingType) => 2 - 0.06 * self.level,
            },
        },
    },
    {
        type: 'barracks',
        name: 'Barracks',
        maxLevel: 20,
        requiredTownhallLevel: 0,
        cost: (level: number) => {
            return {
                wood: getUnitBuildingCost(level, 60),
                stone: getUnitBuildingCost(level, 30),
                iron: getUnitBuildingCost(level, 90),
                food: getUnitBuildingCost(level, 40),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                const intakePerMinute = Math.ceil(self.level / 3) * 3;
                prod.food = -intakePerMinute;
                return prod;
            },
            units: {
                type: 'soldier',
                recruitmentTime: (V: VillageState, self: BuildingType) => 1 - 0.03 * self.level,
            },
        },
    },
    {
        type: 'palace',
        name: 'Palace',
        maxLevel: 10,
        unique: true,
        requiredTownhallLevel: 10,
        cost: (level: number) => {
            return {
                wood: getStorageBuildingCost(level, 200),
                stone: getStorageBuildingCost(level, 240),
                iron: getStorageBuildingCost(level, 110),
                food: getStorageBuildingCost(level, 70),
            };
        },
        timeToBuild: getStandardTimeToBuild,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                prod.food = self.level * -30;
                return prod;
            },
            triggers: {
                onLevelUp: (V: VillageState, self: BuildingType) => {
                    if (self.level === 5 || self.level === 10) {
                        // Create a new hero.
                        V.heroes.push(createHero());
                    }
                },
            },
        },
    },
    {
        type: 'sawmill',
        name: 'Sawmill',
        maxLevel: 5,
        unique: true,
        requiredTownhallLevel: 7,
        cost: (level: number) => {
            return {
                wood: getMultiplierBuildingCost(level, 440),
                stone: getMultiplierBuildingCost(level, 610),
                iron: getMultiplierBuildingCost(level, 870),
                food: getMultiplierBuildingCost(level, 700),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 3,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const resourceProd = V.buildings
                    .filter(b => b.type === 'woodcutter')
                    .map(f => f.behavior.production?.(V, f).wood)
                    .reduce((acc, f) => acc + f, 0);
                const prod = getEmptyResources();
                prod.wood = resourceProd * self.level * 0.05;
                return prod;
            },
        },
    },
    {
        type: 'stonecutter',
        name: 'Stonecutter',
        maxLevel: 5,
        unique: true,
        requiredTownhallLevel: 7,
        cost: (level: number) => {
            return {
                wood: getMultiplierBuildingCost(level, 870),
                stone: getMultiplierBuildingCost(level, 440),
                iron: getMultiplierBuildingCost(level, 610),
                food: getMultiplierBuildingCost(level, 700),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 3,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const resourceProd = V.buildings
                    .filter(b => b.type === 'pit')
                    .map(f => f.behavior.production?.(V, f).stone)
                    .reduce((acc, f) => acc + f, 0);
                const prod = getEmptyResources();
                prod.stone = resourceProd * self.level * 0.05;
                return prod;
            },
        },
    },
    {
        type: 'blacksmith',
        name: 'Blacksmith',
        maxLevel: 5,
        unique: true,
        requiredTownhallLevel: 7,
        cost: (level: number) => {
            return {
                wood: getMultiplierBuildingCost(level, 610),
                stone: getMultiplierBuildingCost(level, 870),
                iron: getMultiplierBuildingCost(level, 440),
                food: getMultiplierBuildingCost(level, 700),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 3,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const resourceProd = V.buildings
                    .filter(b => b.type === 'mine')
                    .map(f => f.behavior.production?.(V, f).iron)
                    .reduce((acc, f) => acc + f, 0);
                const prod = getEmptyResources();
                prod.iron = resourceProd * self.level * 0.05;
                return prod;
            },
        },
    },
    {
        type: 'bakery',
        name: 'Bakery',
        maxLevel: 5,
        unique: true,
        requiredTownhallLevel: 7,
        cost: (level: number) => {
            return {
                wood: getMultiplierBuildingCost(level, 670),
                stone: getMultiplierBuildingCost(level, 740),
                iron: getMultiplierBuildingCost(level, 670),
                food: getMultiplierBuildingCost(level, 520),
            };
        },
        timeToBuild: (level: number) => getStandardTimeToBuild(level) * 3,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const fields = V.buildings.filter(b => b.type === 'field');
                const fieldFoodProd = fields
                    .map(f => f.behavior.production?.(V, f).food)
                    .reduce((acc, f) => acc + f, 0);
                const prod = getEmptyResources();
                prod.food = fieldFoodProd * self.level * 0.05;
                return prod;
            },
        },
    },
    {
        type: 'wonder',
        name: 'World Wonder',
        maxLevel: 1,
        unique: true,
        requiredTownhallLevel: 20,
        cost: () => {
            return {
                wood: 42000,
                stone: 42000,
                iron: 42000,
                food: 38000,
            };
        },
        timeToBuild: () => 120,
        behavior: {
            production: (V: VillageState, self: BuildingType) => {
                const prod = getEmptyResources();
                prod.food = self.level * -300;
                return prod;
            },
            triggers: {
                onLevelUp: (V: VillageState, self: BuildingType) => {
                    if (self.level === 1) {
                        // Gain a lot of culture.
                        V.resources.culture += 18000;
                    }
                },
            },
        },
    },
];
