package com.bernard.greposimu.engine.game;

import java.util.List;
import java.util.Map;

import com.bernard.greposimu.model.DefContext;
import com.bernard.greposimu.model.FightStats;
import com.bernard.greposimu.model.OffContext;
import com.bernard.greposimu.model.game.GameData;
import com.bernard.greposimu.model.game.Power;
import com.bernard.greposimu.model.game.Research;
import com.bernard.greposimu.model.game.Unit;

public class Fight {

	Game g;

	public Fight(Game g) {
		this.g = g;
	}
	public FightStats computeDefStats(DefContext def) {
		
		
		FightStats everyoneStatsBonus = FightStats.zero();
		Map<String,FightStats> unitsBonuses;
		FightStats cityBaseStats;
		
		// Heroes
		unitsBonuses = g.heroes.heroFightBonuses(def.hero, def.heroLevel, false);
		
		// Tower & wall
		cityBaseStats = Buildings.cityBaseStats(def.wallLevel);
		everyoneStatsBonus = FightStats.add(everyoneStatsBonus, Buildings.wallBonus(def.wallLevel));
		if(def.hasTower)
			// Add 10% to all units
			everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.cst(0.1));
		
		// Powers
		
		//TODO powers
		
		// Researches
		if(def.counsellors.contains("divine_selection")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isMythological()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
		if(def.counsellors.contains("phalanx")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isGround()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
		if(def.counsellors.contains("ram")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isNaval()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
		
		// Counsellors
		if(def.counsellors.contains("priest")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isMythological()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
		if(def.counsellors.contains("commander")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isGround()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
		if(def.counsellors.contains("captain")) 
			for(String uid : g.data.units.keySet())
				if(g.data.units.get(uid).isNaval()) 
					unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
		
		// Night Bonus
		if(def.nightBonus)
			everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.cst(1.0));

		// Units
		FightStats total = cityBaseStats.clone();
		for(Unit u : g.data.units.values()) {
			// total = total + ucount * ((1+bonus+bonus) * ustats)
			if(def.units.containsKey(u.id) && def.units.get(u.id) != null)
				total = FightStats.add(total,
						FightStats.prod(def.units.get(u.id),
						FightStats.mul(
						FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(u.id, FightStats.zero()))
						, u.getDefStats())
					));
		}
		
		return total;
	}
	
	public static List<Power> relevantDefPowers(GameData gd) {
		System.out.println(gd.powers);
		return List.of("acumen", "divine_senses", "myrmidion_attack", "trojan_defense", "defense_boost",
				"defense_penalty", "longterm_defense_boost", "assassins_acumen", "rare_defense_boost",
				"epic_defense_boost", "olympic_torch.grepolympia_summer", "olympic_senses.grepolympia_summer", "missions_power_4.missions_dionysia",
				"divine_battle_strategy_rare", "divine_battle_strategy_epic", "naval_battle_strategy_rare",
				"naval_battle_strategy_epic", "land_battle_strategy_rare", "land_battle_strategy_epic",
				"soterias_shrine.not_cast").stream().map(gd.powers::get).map(p -> (Power)p).toList();
	}
	public static List<Research> relevantDefResearch(GameData gd) {
		return List.of("divine_selection","phalanx","ram")
				.stream().map(gd.researches::get).toList();
	}
	public static List<Unit> relevantDefUnits(GameData data) {
		return data.units.values().stream().toList();
	}
	public static List<String> relevantDefCounsellors(GameData data) {
		return List.of("priest","commander","captain");
	}
	public FightStats computeOffStats(DefContext off) {
		//TODO computeOffStats
		throw new UnsupportedOperationException("Simulator not created");
	}
	
	public FightResult simulateFight(OffContext off, DefContext def) {
		//TODO simulateFight
		throw new UnsupportedOperationException("Simulator not created");
	}
	
	public static class FightResult {
		
		Map<String, Integer> def_losses;
		Map<String, Integer> att_losses;
		int wall_loss;
		int att_battle_points;
		int def_battle_points;
		
	}

}
