package space.animefu.starfallhaven;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/** Deterministic regional settlements, diplomacy, and deliberately lightweight strategic AI. */
public final class FactionSimulation {
    public enum Relation { FRIENDLY, NEUTRAL, HOSTILE }
    public enum Strategy { TRADE, DEVELOP, EXPLORE, PRESSURE }

    public static final class Faction {
        public final String id,name;
        public int standing;
        public final List<Settlement> settlements=new ArrayList<>();
        public Relation relation(){return relationFor(standing);}
        Faction(String id,String name,int standing){this.id=id;this.name=name;this.standing=clamp(standing,-100,100);}
    }
    public static final class Settlement {
        public final String id,name,factionId;
        public final int x,y;
        public int population,prosperity,security;
        public Strategy lastStrategy=Strategy.DEVELOP;
        Settlement(String id,String name,String factionId,int x,int y,int population,int prosperity,int security){
            this.id=id;this.name=name;this.factionId=factionId;this.x=x;this.y=y;this.population=population;this.prosperity=prosperity;this.security=security;
        }
    }

    public final long seed;
    public int strategicTurn;
    public final List<Faction> factions=new ArrayList<>();

    private FactionSimulation(long seed){this.seed=seed;}
    public static FactionSimulation generate(long seed,RegionalMap map,int landingX,int landingY){
        FactionSimulation state=new FactionSimulation(seed);
        String[][] identities={{"skyloom","Skyloom Cooperative"},{"emberline","Emberline Wardens"},{"quiet-comet","Quiet Comet Circle"}};
        int[] standings={38,4,-42};
        List<RegionalMap.Cell> choices=new ArrayList<>(map.validLandingSites());
        Collections.sort(choices,new Comparator<RegionalMap.Cell>(){public int compare(RegionalMap.Cell a,RegionalMap.Cell b){
            long ah=RegionalMap.hash(seed,a.x,a.y,211),bh=RegionalMap.hash(seed,b.x,b.y,211);return ah==bh?0:(ah<bh?-1:1);
        }});
        boolean[][] used=new boolean[map.width][map.height];
        if(map.inside(landingX,landingY))used[landingX][landingY]=true;
        for(int i=0;i<identities.length;i++){
            Faction faction=new Faction(identities[i][0],identities[i][1],standings[i]);state.factions.add(faction);
            int count=i==1?2:1;
            for(int j=0;j<count;j++){
                RegionalMap.Cell site=choose(choices,used,landingX,landingY,i,j);
                used[site.x][site.y]=true;
                int pop=14+(int)(RegionalMap.hash(seed,site.x,site.y,301+i)%23);
                int prosperity=28+(int)(RegionalMap.hash(seed,site.x,site.y,401+i)%35);
                int security=30+(int)(RegionalMap.hash(seed,site.x,site.y,501+i)%40);
                String id=faction.id+"-"+(j+1),name=settlementName(i,j);
                faction.settlements.add(new Settlement(id,name,faction.id,site.x,site.y,pop,prosperity,security));
            }
        }
        return state;
    }
    private static RegionalMap.Cell choose(List<RegionalMap.Cell> choices,boolean[][] used,int lx,int ly,int faction,int index){
        RegionalMap.Cell fallback=choices.get((faction*3+index)%choices.size());
        for(RegionalMap.Cell cell:choices){int distance=Math.abs(cell.x-lx)+Math.abs(cell.y-ly);if(!used[cell.x][cell.y]&&distance>=3+faction)return cell;}return fallback;
    }
    private static String settlementName(int faction,int index){String[][] names={{"Prism Orchard"},{"Cinderwatch","Copper Relay"},{"Moonwake Refuge"}};return names[faction][index];}

    public static Relation relationFor(int standing){return standing>=25?Relation.FRIENDLY:standing<=-25?Relation.HOSTILE:Relation.NEUTRAL;}
    public Faction faction(String id){for(Faction f:factions)if(f.id.equals(id))return f;return null;}
    public List<Settlement> settlements(){List<Settlement> out=new ArrayList<>();for(Faction f:factions)out.addAll(f.settlements);return Collections.unmodifiableList(out);}
    public void changeStanding(String factionId,int amount){Faction faction=faction(factionId);if(faction!=null)faction.standing=clamp(faction.standing+amount,-100,100);}

    public void advanceToDay(int day){while(strategicTurn<Math.max(0,day-1))advanceTurn();}
    public void advanceTurn(){
        int turn=++strategicTurn;
        for(Faction faction:factions)for(Settlement settlement:faction.settlements){
            long roll=RegionalMap.hash(seed^turn,settlement.x,settlement.y,617+(int)settlement.id.hashCode());
            Relation relation=faction.relation();
            Strategy strategy=relation==Relation.HOSTILE?(roll%4==0?Strategy.DEVELOP:Strategy.PRESSURE):relation==Relation.FRIENDLY?(roll%3==0?Strategy.TRADE:Strategy.DEVELOP):(roll%2==0?Strategy.EXPLORE:Strategy.DEVELOP);
            settlement.lastStrategy=strategy;
            switch(strategy){
                case TRADE:settlement.prosperity+=3;settlement.population+=turn%3==0?1:0;faction.standing=clamp(faction.standing+1,-100,100);break;
                case DEVELOP:settlement.prosperity+=2;settlement.security+=1;settlement.population+=turn%2;break;
                case EXPLORE:settlement.prosperity+=1;settlement.security+=2;break;
                case PRESSURE:settlement.security+=3;settlement.prosperity=Math.max(0,settlement.prosperity-1);faction.standing=clamp(faction.standing-1,-100,100);break;
            }
            settlement.population=clamp(settlement.population,1,999);settlement.prosperity=clamp(settlement.prosperity,0,100);settlement.security=clamp(settlement.security,0,100);
        }
    }

    static FactionSimulation empty(long seed,int turn){FactionSimulation state=new FactionSimulation(seed);state.strategicTurn=turn;return state;}
    static Faction addFaction(FactionSimulation state,String id,String name,int standing){Faction f=new Faction(id,name,standing);state.factions.add(f);return f;}
    static Settlement addSettlement(Faction faction,String id,String name,int x,int y,int population,int prosperity,int security,Strategy strategy){Settlement s=new Settlement(id,name,faction.id,x,y,population,prosperity,security);s.lastStrategy=strategy;faction.settlements.add(s);return s;}
    private static int clamp(int value,int low,int high){return Math.max(low,Math.min(high,value));}
}
