package electrosphere.game.server.world;

import java.util.LinkedList;
import java.util.List;

import electrosphere.engine.Globals;
import electrosphere.game.server.character.Character;
import electrosphere.game.server.character.CharacterDataStrings;
import electrosphere.game.server.character.CharacterUtils;
import electrosphere.game.server.character.diety.Diety;
import electrosphere.game.server.civilization.Civilization;
import electrosphere.game.server.race.model.Race;
import electrosphere.game.server.race.model.RaceMap;
import electrosphere.game.server.structure.virtual.Structure;
import electrosphere.game.server.symbolism.model.Symbol;
import electrosphere.game.server.town.Town;

import java.util.Random;
import org.joml.Vector2i;

/**
 * Server macro level data
 */
public class MacroData {
    
    List<Character> initialDieties = new LinkedList<Character>();
    List<Race> races = new LinkedList<Race>();
    List<Character> characters = new LinkedList<Character>();
    List<Character> aliveCharacters = new LinkedList<Character>();
    List<Civilization> civilizations = new LinkedList<Civilization>();
    List<Town> towns = new LinkedList<Town>();
    List<Structure> structures = new LinkedList<Structure>();
    
    
    static Character generateInitialDiety(long seed){
        Character rVal = new Character();
        
        
        Diety diety = Diety.generateDiety(seed);
        CharacterUtils.addDiety(rVal, diety);
        
        
        return rVal;
    }
    

    static final int MAX_PLACEMENT_ATTEMPTS = 50;

    public static MacroData generateWorld(long seed){
        Random random = new Random(seed);
        MacroData rVal = new MacroData();
        
        //generate initial dieties
        int numDieties = 3 + Math.abs(random.nextInt()) % 7;
        for(int i = 0; i < numDieties; i++){
            Character diety = generateInitialDiety(random.nextLong());
            rVal.initialDieties.add(diety);
            rVal.characters.add(diety);
        }
        
        //generate initial races
        if(Globals.gameConfigCurrent.getRaceMap().getSymbolismMap().size() < 3){
            for(Race race : Globals.gameConfigCurrent.getRaceMap().getSymbolismMap()){
                rVal.races.add(race);
            }
        } else {
            RaceMap raceMap = Globals.gameConfigCurrent.getRaceMap();
            int numRacesToGenerate = 3 + random.nextInt(Math.min(raceMap.getSymbolismMap().size() - 3,7));
            for(int i = 0; i < numRacesToGenerate; i++){
                Race raceToAdd = raceMap.getSymbolismMap().get(random.nextInt(raceMap.getSymbolismMap().size()));
                while(rVal.races.contains(raceToAdd)){
                    raceToAdd = raceMap.getSymbolismMap().get(random.nextInt(raceMap.getSymbolismMap().size()));
                }
                rVal.races.add(raceToAdd);
            }
        }
        
        //spawn initial characters in each race
        //find initial positions to place characters at per race
        //generate initial characters
        //place them
        List<Vector2i> occupiedStartingPositions = new LinkedList<Vector2i>();
        for(Race race : rVal.races){
            boolean foundPlacementLocation = false;
            int attempts = 0;
            while(!foundPlacementLocation){
                // Vector2i start = new Vector2i(random.nextInt(Globals.serverTerrainManager.getWorldDiscreteSize()),random.nextInt(Globals.serverTerrainManager.getWorldDiscreteSize()));
                // //are we above sea level?
                // if(Globals.serverTerrainManager.getDiscreteValue(start.x, start.y) > 25){ //TODO: Set to actual sea level value
                //     //is this position already occupied?
                //     boolean match = false;
                //     for(Vector2i known : occupiedStartingPositions){
                //         if(known.x == start.x && known.y == start.y){
                //             match = true;
                //             break;
                //         }
                //     }
                //     if(!match){
                //         //occupy position
                //         occupiedStartingPositions.add(start);
                //         foundPlacementLocation = true;
                //         //make characters
                //         int numCharactersToMake = 5 + random.nextInt(20);
                //         for(int i = 0; i < numCharactersToMake; i++){
                //             Character character = new Character();
                //             CharacterUtils.addDiscretePosition(character, start.x, start.y);
                //             CharacterUtils.addRace(character, race);
                //             rVal.characters.add(character);
                //             rVal.aliveCharacters.add(character);
                //         }
                //     }
                // }
                // attempts++;
                // if(attempts > MAX_PLACEMENT_ATTEMPTS){
                //     break;
                // }
            }
        }
        
        return rVal;
    }
    
    public List<Character> getAliveCharacters(){
        return aliveCharacters;
    }
    
    public List<Civilization> getCivilizations(){
        return civilizations;
    }
    
    public void addCivilization(Civilization civilization){
        civilizations.add(civilization);
    }
    
    public List<Town> getTowns(){
        return towns;
    }
    
    public void addTown(Town town){
        towns.add(town);
    }
    
    public List<Structure> getStructures(){
        return structures;
    }
    
    public void addStructure(Structure structure){
        structures.add(structure);
    }
    
    public void describeWorld(){
        System.out.println("Initial dieties");
        System.out.println("==========================");
        for(Character chara : initialDieties){
            System.out.println("Diety");
            Diety diety = CharacterUtils.getDiety(chara);
            for(Symbol symbol : diety.getSymbols()){
                System.out.print(symbol.getName() + " ");
            }
            System.out.println("\n");
        }
        System.out.println("==========================");
        System.out.println("\n\n");
        System.out.println("Initial races");
        System.out.println("==========================");
        for(Race race : races){
            System.out.println(race.getName());
            int numCharsOfRace = 0;
            //n*m complexity - yikes! - as long as we're not making a million chars at start this should be _ok_
            for(Character chara : characters){
                if(chara.containsKey(CharacterDataStrings.RACE)){
                    if(CharacterUtils.getRace(chara).equals(race)){
                        numCharsOfRace++;
                    }
                }
            }
            System.out.println(numCharsOfRace + " initial characters");
            System.out.println("\n");
        }
        System.out.println("==========================");
    }
    
}
