package data.scripts.hullmods;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.BaseHullMod;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.DamageType;
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.combat.WeaponAPI;
import com.fs.starfarer.api.graphics.SpriteAPI;
import com.fs.starfarer.api.util.IntervalUtil;
import data.scripts.util.SWP_Multi;
import data.scripts.util.SWP_Util;
import java.awt.Color;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.combat.AIUtils;
import org.lazywizard.lazylib.combat.entities.AnchoredEntity;

public class SWP_ExcelsiorReactor extends BaseHullMod {

    public static final float BEAM_DAMAGE_REDUCTION = 50f;
    public static final float EMP_DAMAGE_REDUCTION = 50f;
    public static final float OVERLOAD_MULT = 50f;
    public static final float VENT_BONUS = 200f;

    private static final String DATA_KEY = "SWP_ExcelsiorReactor";

    private static final Color GLOW_COLOR_400 = new Color(128, 0, 0);
    private static final Color GLOW_COLOR_6000 = new Color(128, 0, 255);
    private static final float PULSATE_FREQ_400 = 0.5f;
    private static final float PULSATE_FREQ_6000 = 3f;
    private static final float PULSATE_MAG_400 = 0.5f;
    private static final float PULSATE_MAG_6000 = 0.3f;
    private static final float FLICKER_RATE_400 = 3f;
    private static final float FLICKER_RATE_6000 = 30f;
    private static final float FLICKER_MAG_400 = 0.2f;
    private static final float FLICKER_MAG_6000 = 0.8f;

    private final IntervalUtil interval = new IntervalUtil(0.1f, 0.1f);

    @Override
    public void advanceInCombat(ShipAPI ship, float amount) {
        CombatEngineAPI engine = Global.getCombatEngine();
        if (!engine.getCustomData().containsKey(DATA_KEY)) {
            engine.getCustomData().put(DATA_KEY, new LocalData());
        }

        final LocalData localData = (LocalData) engine.getCustomData().get(DATA_KEY);
        Map<ShipAPI, Float> tPulsateMap = localData.tPulsateMap;

        if (!tPulsateMap.containsKey(ship)) {
            tPulsateMap.put(ship, 0f);
        }
        float tPulsate = tPulsateMap.get(ship);

        WeaponAPI glow = null;
        List<WeaponAPI> weapons = ship.getAllWeapons();
        for (WeaponAPI weapon : weapons) {
            if (weapon.getId().contentEquals("swp_excelsior_auxglow")) {
                glow = weapon;
                break;
            }
        }

        if (glow != null) {
            float effectLevel = (ship.getFluxTracker().getCurrFlux() - 400f) / (6000f - 400f);
            float fadeLevel = ship.getFluxTracker().getCurrFlux() / 400f;
            if (effectLevel > 0f) {
                glow.getAnimation().setFrame(1);
                SpriteAPI sprite = glow.getSprite();

                fadeLevel = 1f;

                float pulsateFreq = SWP_Util.lerp(PULSATE_FREQ_400, PULSATE_FREQ_6000, effectLevel);
                float pulsateMag = SWP_Util.lerp(PULSATE_MAG_400, PULSATE_MAG_6000, effectLevel);
                tPulsate += pulsateFreq * amount;
                fadeLevel *= 1f + ((pulsateMag * 0.5f) * (float) Math.sin(tPulsate * Math.PI * 2));

                float flickerRate = SWP_Util.lerp(FLICKER_RATE_400, FLICKER_RATE_6000, effectLevel);
                float flickerMag = SWP_Util.lerp(FLICKER_MAG_400, FLICKER_MAG_6000, effectLevel);
                float flickerChance = flickerRate * amount;
                if (Math.random() < flickerChance) {
                    fadeLevel *= 1f - flickerMag;
                }

                int red = SWP_Util.clamp255((int) ((GLOW_COLOR_400.getRed() + (effectLevel * (GLOW_COLOR_6000.getRed() - GLOW_COLOR_400.getRed()))) * fadeLevel));
                int green = SWP_Util.clamp255((int) ((GLOW_COLOR_400.getGreen() + (effectLevel * (GLOW_COLOR_6000.getGreen() - GLOW_COLOR_400.getGreen()))) * fadeLevel));
                int blue = SWP_Util.clamp255((int) ((GLOW_COLOR_400.getBlue() + (effectLevel * (GLOW_COLOR_6000.getBlue() - GLOW_COLOR_400.getBlue()))) * fadeLevel));

                sprite.setAdditiveBlend();
                sprite.setColor(new Color(red, green, blue, 255));
            } else if (fadeLevel > 0f) {
                glow.getAnimation().setFrame(1);
                SpriteAPI sprite = glow.getSprite();

                int red = SWP_Util.clamp255((int) (GLOW_COLOR_400.getRed() * fadeLevel));
                int green = SWP_Util.clamp255((int) (GLOW_COLOR_400.getGreen() * fadeLevel));
                int blue = SWP_Util.clamp255((int) (GLOW_COLOR_400.getBlue() * fadeLevel));

                sprite.setAdditiveBlend();
                sprite.setColor(new Color(red, green, blue, 255));
            } else {
                glow.getAnimation().setFrame(0);
            }
        }

        if (Global.getCombatEngine().isPaused()) {
            return;
        }

        tPulsateMap.put(ship, tPulsate);

        interval.advance(amount);
        if (ship.getFluxTracker().isOverloaded()) {
            if (interval.intervalElapsed()) {
                if (Math.random() < 0.2) {
                    float shipRadius = SWP_Util.effectiveRadius(ship);

                    Global.getCombatEngine().spawnEmpArc(ship,
                            MathUtils.getRandomPointOnCircumference(
                                    ship.getLocation(),
                                    shipRadius
                                    * ((float) Math.random() + 1f)),
                            ship, ship, DamageType.ENERGY, 100f, 100f, 500f, null, 15f,
                            new Color(255, 150, 200),
                            new Color(255, 150, 255));
                }
            }
        } else if (ship.getFluxTracker().isVenting()) {
            if (interval.intervalElapsed()) {
                float scale
                        = ship.getMutableStats().getVentRateMult().getModifiedValue() * 2f / 3f
                        * ship.getMutableStats().getFluxDissipation().getModifiedValue() / 50f;
                if (Math.random() < 0.3 * Math.sqrt(scale)) {
                    float range = (float) Math.sqrt(ship.getFluxTracker().getCurrFlux()) * (float) Math.sqrt(scale) * 4f;
                    List<ShipAPI> targets = AIUtils.getNearbyEnemies(ship, range);
                    if (targets.size() > 0) {
                        ShipAPI target = targets.get(MathUtils.getRandom().nextInt(targets.size()));
                        if (SWP_Multi.isWithinEmpRange(ship.getLocation(), range * 1.25f, target)) {
                            Global.getCombatEngine().spawnEmpArc(ship,
                                    MathUtils.getRandomPointOnCircumference(
                                            ship.getLocation(), 30f),
                                    ship, target,
                                    DamageType.ENERGY,
                                    70f * scale, 70f * scale, range * 1.25f,
                                    "swp_excelsior_vent", 5f * scale,
                                    new Color(255, 50, 150), new Color(255, 100, 200));
                        }
                    } else {
                        AnchoredEntity entity = new AnchoredEntity(ship, MathUtils.getRandomPointOnCircumference(
                                ship.getLocation(), 30f));
                        Global.getCombatEngine().spawnEmpArc(ship,
                                MathUtils.getRandomPointOnCircumference(
                                        ship.getLocation(), range),
                                entity, entity,
                                DamageType.ENERGY, 0f, 0f, range * 2f, null, 5f * scale,
                                new Color(255, 50, 150),
                                new Color(255, 100, 200));
                    }
                }
            }
        }
    }

    @Override
    public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
        stats.getOverloadTimeMod().modifyMult(id, OVERLOAD_MULT / 100f);
        stats.getVentRateMult().modifyPercent(id, VENT_BONUS);
        stats.getEmpDamageTakenMult().modifyPercent(id, -EMP_DAMAGE_REDUCTION);
        stats.getBeamDamageTakenMult().modifyPercent(id, -BEAM_DAMAGE_REDUCTION);
    }

    @Override
    public String getDescriptionParam(int index, HullSize hullSize) {
        switch (index) {
            case 0:
                return "" + (int) OVERLOAD_MULT;
            case 1:
                return "" + (int) VENT_BONUS;
            case 2:
                return "" + (int) EMP_DAMAGE_REDUCTION;
            case 3:
                return "" + (int) BEAM_DAMAGE_REDUCTION;
            default:
                break;
        }
        return null;
    }

    @Override
    public boolean isApplicableToShip(ShipAPI ship) {
        return false;
    }

    private static final class LocalData {

        final Map<ShipAPI, Float> tPulsateMap = new HashMap<>(50);
    }
}
