package data.scripts.hullmods;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.campaign.CampaignFleetAPI;
import com.fs.starfarer.api.campaign.SectorAPI;
import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
import com.fs.starfarer.api.characters.PersonAPI;
import com.fs.starfarer.api.combat.MutableShipStatsAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.ShipAPI.HullSize;
import com.fs.starfarer.api.fleet.FleetMemberAPI;
import com.fs.starfarer.api.impl.campaign.ids.HullMods;
import com.fs.starfarer.api.impl.hullmods.BaseLogisticsHullMod;
import data.scripts.everyframe.SWP_BlockedHullmodDisplayScript;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class SWP_ExtremeModifications extends BaseLogisticsHullMod {

    private static final float ENGINE_MALFUNCTION_PROB = 0.02f;
    private static final float WEAPON_MALFUNCTION_PROB = 0.02f;
    private static final float REFIT_TIME_PENALTY = 0.3f;

    private static final Set<String> BLOCKED_HULLMODS = new HashSet<>(1);

    static {
        BLOCKED_HULLMODS.add("efficiency_overhaul");
    }

    private static BlackMagic magic = null;

    public static void addMember(FleetMemberAPI member) {
        if (magic == null || magic.isDone()) {
            magic = new BlackMagic();
            Thread magicThread = new Thread(magic);
            magicThread.start();
        }
        magic.addMember(member);
    }

    public static void addShip(ShipAPI ship) {
        if (magic == null || magic.isDone()) {
            magic = new BlackMagic();
            Thread magicThread = new Thread(magic);
            magicThread.start();
        }
        magic.addShip(ship);
    }

    @Override
    public void applyEffectsAfterShipCreation(ShipAPI ship, String id) {
        for (String tmp : BLOCKED_HULLMODS) {
            if (ship.getVariant().getHullMods().contains(tmp)) {
                ship.getVariant().removeMod(tmp);
                SWP_BlockedHullmodDisplayScript.showBlocked(ship);
            }
        }
    }

    @Override
    public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
        stats.getWeaponMalfunctionChance().modifyFlat(id, WEAPON_MALFUNCTION_PROB);
        stats.getEngineMalfunctionChance().modifyFlat(id, ENGINE_MALFUNCTION_PROB);
        stats.getFighterRefitTimeMult().modifyPercent(id, REFIT_TIME_PENALTY * 100f);

        ShipAPI ship = (ShipAPI) stats.getEntity();
        if (ship == null) {
            return;
        }
        SectorAPI sector = Global.getSector();
        if (sector != null) {
            CampaignFleetAPI player = Global.getSector().getPlayerFleet();
            if (player != null) {
                for (FleetMemberAPI member : player.getFleetData().getMembersListCopy()) {
                    if (member.getId() != null && ship.getFleetMemberId() != null && member.getId().contentEquals(
                            ship.getFleetMemberId())) {
                        addMember(member);
                        return;
                    }
                }
                addShip(ship);
            } else {
                addShip(ship);
            }
        } else {
            addShip(ship);
        }
    }

    @Override
    public String getDescriptionParam(int index, HullSize hullSize) {
        if (index == 0) {
            return "" + (int) REFIT_TIME_PENALTY + "%";
        }
        return null;
    }

    @Override
    public String getUnapplicableReason(ShipAPI ship) {
        if ((ship != null) && ship.getVariant().hasHullMod(HullMods.CIVGRADE) && !ship.getVariant().hasHullMod(HullMods.MILITARIZED_SUBSYSTEMS)) {
            return "Can not be installed on civilian ships";
        }
        if ((ship != null) && ship.getVariant().hasHullMod("efficiency_overhaul")) {
            return "Incompatible with Efficiency Overhaul";
        }

        return super.getUnapplicableReason(ship);
    }

    @Override
    public boolean isApplicableToShip(ShipAPI ship) {
        if ((ship != null) && ship.getVariant().hasHullMod(HullMods.CIVGRADE) && !ship.getVariant().hasHullMod(HullMods.MILITARIZED_SUBSYSTEMS)) {
            return false;
        }
        if ((ship != null) && ship.getVariant().hasHullMod("efficiency_overhaul")) {
            return false;
        }
        return super.isApplicableToShip(ship);
    }

    public static final class BlackMagic implements Runnable {

        private boolean done = false;

        private final Set<WeakReference<FleetMemberAPI>> members = new LinkedHashSet<>(5);
        private final Set<WeakReference<ShipAPI>> ships = new LinkedHashSet<>(5);

        @Override
        @SuppressWarnings("SleepWhileInLoop")
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                SectorAPI sector = Global.getSector();
                MutableCharacterStatsAPI stats = null;
                if (sector != null) {
                    PersonAPI player = sector.getPlayerPerson();
                    if (player != null) {
                        stats = player.getStats();
                    }
                }

                synchronized (this) {
                    Iterator<WeakReference<ShipAPI>> iter = ships.iterator();
                    while (iter.hasNext()) {
                        WeakReference<ShipAPI> reference = iter.next();
                        ShipAPI ship = reference.get();
                        if (ship == null) {
                            iter.remove();
                            continue;
                        }

                        if (!ship.getVariant().hasHullMod("swp_extrememods")) {
                            if (ship.getVariant().computeOPCost(stats) > ship.getHullSpec().getOrdnancePoints(stats)) {
                                ship.getVariant().addMod("swp_extrememods");
                            } else if (sector != null && !sector.isPaused()) {
                                iter.remove();
                            }
                        }
                    }

                    Iterator<WeakReference<FleetMemberAPI>> iter2 = members.iterator();
                    while (iter2.hasNext()) {
                        WeakReference<FleetMemberAPI> reference = iter2.next();
                        FleetMemberAPI member = reference.get();
                        if (member == null) {
                            iter2.remove();
                            continue;
                        }

                        if (!member.getVariant().hasHullMod("swp_extrememods")) {
                            if (member.getVariant().computeOPCost(stats) > member.getHullSpec().getOrdnancePoints(stats)) {
                                member.getVariant().addMod("swp_extrememods");
                            } else if (sector != null && !sector.isPaused()) {
                                iter2.remove();
                            }
                        }
                    }

                    if (ships.isEmpty() && members.isEmpty()) {
                        break;
                    }
                }

                try {
                    Thread.sleep(250); // The whole point of using a separate thread is we don't know when the ship removes the hullmod, so we gotta sleep
                } catch (InterruptedException ex) {
                    break;
                }
            }

            done = true;
        }

        private synchronized void addMember(FleetMemberAPI member) {
            members.add(new WeakReference<>(member));
        }

        private synchronized void addShip(ShipAPI ship) {
            ships.add(new WeakReference<>(ship));
        }

        private boolean isDone() {
            return done;
        }
    }
}
