package theorycrafter.tournaments.impl

import eve.data.*
import eve.data.typeid.*
import theorycrafter.tournaments.*
import theorycrafter.tournaments.TournamentRules.FittingRules
import theorycrafter.ui.fiteditor.PackForBattleConfiguration
import theorycrafter.ui.fiteditor.isEmpireFactionHybridChargeProperForShipType


/**
 * The descriptor for Charity Cup (2025).
 */
val CharityCup = TournamentDescriptor(
    id = "cc25",
    name = "Charity Cup 2025",
    shortName = "CC25",
    rulesFactory = ::charityCup2025Rules,
    winner = "RageSub Cancel Quit"
)


private val ShipPositionSpecs: List<ShipPositionSpec> = listOf(
    ShipPositionSpec(
        name = "Battleship",
        prefix = "1.",
        points = 22,
        shipTypeNames = listOf(
            "Apocalypse",
            "Armageddon",
            "Abaddon",
            "Raven",
            "Scorpion",
            "Rokh",
            "Megathron",
            "Dominix",
            "Hyperion",
            "Tempest",
            "Typhoon",
            "Maelstrom"
        )
    ),
    ShipPositionSpec(
        name = "Battlecruiser",
        prefix = "2.",
        points = 21,
        shipTypeNames = listOf(
            "Harbinger Navy Issue",
            "Prophecy Navy Issue",
            "Drake Navy Issue",
            "Ferox Navy Issue",
            "Brutix Navy Issue",
            "Myrmidon Navy Issue",
            "Hurricane Fleet Issue",
            "Cyclone Fleet Issue",
            "Harbinger",
            "Prophecy",
            "Ferox",
            "Drake",
            "Brutix",
            "Myrmidon",
            "Cyclone",
            "Hurricane",
            "Gnosis",
            "Oracle",
            "Naga",
            "Tornado",
            "Talos"
        ),
    ),
    ShipPositionSpec(
        name = "Cruiser",
        prefix = "3.",
        points = 19,
        shipTypeNames = listOf(
            "Devoter",
            "Phobos",
            "Onyx",
            "Broadsword",
            "Vedmak",
            "Ashimmu",
            "Cynabal",
            "Orthrus",
            "Phantasm",
            "Stratios",
            "Vigilant",
            "Augoror Navy Issue",
            "Omen Navy Issue",
            "Caracal Navy Issue",
            "Osprey Navy Issue",
            "Exequror Navy Issue",
            "Vexor Navy Issue",
            "Scythe Fleet Issue",
            "Stabber Fleet Issue",
            "Arbitrator",
            "Blackbird",
            "Bellicose",
            "Celestis"
        )
    ),
    ShipPositionSpec(
        name = "Logistics",
        prefix = "4.",
        points = 18,
        shipTypeNames = listOf(
            "Augoror",
            "Osprey",
            "Exequror",
            "Scythe",
            "Scalpel",
            "Kirin",
            "Deacon",
            "Thalia"
        )
    ),
    ShipPositionSpec(
        name = "Destroyer",
        prefix = "5.",
        points = 11,
        shipTypeNames = listOf(
            "Mekubal",
            "Mamba",
            "Tholos",
            "Kikimora",
            "Heretic",
            "Flycatcher",
            "Eris",
            "Sabre",
            "Pontifex",
            "Bifrost",
            "Stork",
            "Magus",
            "Confessor",
            "Svipul",
            "Jackdaw",
            "Hecate",
            "Coercer Navy Issue",
            "Thrasher Fleet Issue",
            "Cormorant Navy Issue",
            "Catalyst Navy Issue"
        )
    ),
    ShipPositionSpec(
        name = "Frigate",
        prefix = "6.",
        points = 9,
        shipTypeNames = listOf(
            "Astero",
            "Cruor",
            "Daredevil",
            "Dramiel",
            "Garmur",
            "Succubus",
            "Worm",
            "Sentinel",
            "Kitsune",
            "Keres",
            "Hyena",
            "Malediction",
            "Crusader",
            "Crow",
            "Raptor",
            "Ares",
            "Taranis",
            "Stiletto",
            "Claw",
            "Vengeance",
            "Retribution",
            "Harpy",
            "Hawk",
            "Jaguar",
            "Wolf",
            "Enyo",
            "Ishkur",
            "Crucifier",
            "Maulus",
            "Griffin",
            "Vigil"
        )
    )
)


/**
 * The composition rules for Charity Cup 2025.
 */
private class CharityCup2025CompositionRules(
    eveData: EveData
): BasicDraftCompositionRules(
    eveData = eveData,
    positionSpecs = ShipPositionSpecs
)


/**
 * The fitting rules for Charity Cup 2025.
 */
private class CharityCup2025FittingRules(
    private val eveData: EveData
): FittingRules {


    override fun isModuleLegal(moduleType: ModuleType, shipType: ShipType, isFlagship: Boolean): Boolean {
        with(eveData) {
            if (moduleType.mutation != null)
                return false

            if (!moduleType.isTech1Item && !moduleType.isTech2Item)
                return false

            return when {
                moduleType.isRemoteRepairer -> shipType.isLogistics
                moduleType.isEcm() || moduleType.isBurstJammer() -> isEcmLegal(moduleType, shipType)
                moduleType.isWeaponDisruptor() -> isWeaponDisruptorLegal(moduleType, shipType)
                moduleType.isRemoteSensorDampener() -> isRemoteSensorDampenerLegal(moduleType, shipType)
                moduleType.isMicroJumpFieldGenerator() -> false
                moduleType.isCloakingDevice() -> false
                moduleType.isRig -> moduleType.isTech1Item
                else -> true
            }
        }
    }


    override fun fitModulesLegality(moduleTypes: List<ModuleType>, shipType: ShipType, isFlagship: Boolean): List<String?> {
        with(eveData) {
            val regularIllegality = moduleTypes.map {
                if (isModuleLegal(it, shipType, isFlagship)) null else "Module is illegal here"
            }
            val illegalityByGroup = moduleIllegalityByGroup(
                moduleTypes = moduleTypes,
                maxInGroup = {
                    when (it) {
                        groups.armorPlate -> if (shipType.isBattleship) 1 else Unlimited
                        groups.shieldExtender -> if (shipType.isBattleship) 2 else Unlimited
                        groups.remoteCapacitorTransmitter -> 1
                        groups.warpDisruptFieldGenerator -> 1
                        else -> Unlimited
                    }
                },
                additionalChecks = arrayOf(
                    { group, countByGroup ->
                        if (shipType.isBattleship && !isAtMostOneActiveRepModule(group, countByGroup))
                            "At most one active repair module is allowed on a battleship"
                        else
                            null
                    }
                )
            )

            return combineIllegalityReasons(regularIllegality, illegalityByGroup)
        }
    }


    override fun isChargeLegal(chargeType: ChargeType?, moduleType: ModuleType): Boolean {
        with(eveData) {
            if (moduleType.isInterdictionSphereLauncher())
                return (chargeType != null) && chargeType.isStasisWebificationProbe
            return isChargeLegal(chargeType)
        }
    }


    override fun isDroneLegal(droneType: DroneType): Boolean {
        return with(eveData) {
            when {
                droneType.name == "Gecko" -> false
                droneType.isSentry -> droneType.isTech1Item
                droneType.isCombatDrone() -> droneType.isTech1Item || droneType.isEmpireNavyFactionItem
                droneType.isShieldMaintenanceBot() ||
                        droneType.isArmorMaintenanceBot() ||
                        droneType.isHullMaintenanceBot() -> droneType.isTech1Item
                droneType.isStasisWebifyingDrone() ||
                        droneType.isTargetPaintingDrone() ||
                        droneType.isEnergyNeutralizerDrone() ||
                        droneType.isEcmDrone() ||
                        droneType.isSensorDampeningDrone() ||
                        droneType.isTrackingDisruptingDrone() -> true
                else -> false
            }
        }
    }


    override fun isImplantLegal(implantType: ImplantType): Boolean {
        return implantType.is010203Hardwiring
    }


    override fun isCargoItemLegal(itemType: EveItemType): Boolean {
        with(eveData) {
            if (itemType.isCargoContainer)
                return false

            return when (itemType) {
                is ChargeType -> isChargeLegal(itemType)
                is ImplantType -> isImplantLegal(itemType)
                is BoosterType -> isBoosterLegal(itemType)
                else -> true
            }
        }
    }


    override val packForBattleConfiguration: PackForBattleConfiguration
        get() = PackForBattleConfig


}


/**
 * The rules for Charity Cup 2025.
 */
private fun charityCup2025Rules(eveData: EveData) =
    TournamentRules(
        compositionRules = CharityCup2025CompositionRules(eveData),
        fittingRules = CharityCup2025FittingRules(eveData)
    )


/**
 * Returns whether the given ECM module is legal on the given ship type.
 */
context(EveData)
private fun isEcmLegal(moduleType: ModuleType, shipType: ShipType): Boolean {
    return moduleType.isTech1Item && (shipType.name in EcmShips)
}


/**
 * Returns whether the given weapon disruption module is legal on the given ship type.
 */
context(EveData)
private fun isWeaponDisruptorLegal(moduleType: ModuleType, shipType: ShipType): Boolean {
    return moduleType.isTech1Item && (shipType.name in WeaponDisruptionShips)
}


/**
 * Returns whether the given sensor dampener module is legal on the given ship type.
 */
context(EveData)
private fun isRemoteSensorDampenerLegal(moduleType: ModuleType, shipType: ShipType): Boolean {
    return moduleType.isTech1Item && (shipType.name in SensorDampeningShips)
}


/**
 * Checks whether the modules don't contain more than one
 */
context(EveData)
private fun isAtMostOneActiveRepModule(group: TypeGroup, countByGroup: Map<in TypeGroup, Int>): Boolean {
    return isAtMost(
        max = 1,
        kind = group,
        countByKind = countByGroup,
        groups.shieldBooster,
        groups.ancillaryShieldBooster,
        groups.armorRepairer,
        groups.ancillaryArmorRepairer,
        groups.hullRepairer
    )
}


/**
 * Returns whether the charge is legal, whether in a module or in the cargohold.
 */
context(EveData)
private fun isChargeLegal(chargeType: ChargeType?): Boolean {
    return when {
        chargeType == null -> true
        chargeType.isInterdictionSphereLauncherProbe() -> chargeType.isStasisWebificationProbe
        chargeType.isAmmo() -> when {
            chargeType.isTech2Item -> true
            chargeType.isMissile()
                    || chargeType.isProjectileAmmo()
                    || chargeType.isFrequencyCrystalAmmo()
                    || chargeType.isHybridChargeAmmo() -> chargeType.isEmpireNavyFactionItem
            else -> true
        }
        else -> true
    }
}


/**
 * The configuration for the "Pack for Battle" dialog.
 */
private val PackForBattleConfig = object: PackForBattleConfiguration {


    context(EveData)
    override fun script(chargeType: ChargeType): Boolean {
        return isChargeLegal(chargeType)
    }


    context(EveData)
    override fun interdictionSphereLauncherProbe(chargeType: ChargeType): Boolean {
        return isChargeLegal(chargeType)
    }


    context(EveData)
    override fun ammo(shipType: ShipType, moduleType: ModuleType, chargeType: ChargeType): Boolean {
        return when {
            chargeType.isBomb() -> true
            chargeType.isDefenderMissile() -> true
            chargeType.isTech2Item -> true
            chargeType.isBreacherPod() -> true
            moduleType.isHybridWeapon() -> isEmpireFactionHybridChargeProperForShipType(shipType, chargeType)
            else -> chargeType.isEmpireNavyFactionItem
        }
    }


}
