using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Static;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;

namespace PkmnLib.Dynamic.ScriptHandling;

/// <summary>
/// This interface is used to allow scripts to run when they are removed from their owner.
/// </summary>
public interface IScriptOnRemove
{
    /// <summary>
    /// This function is ran when this script stops being in effect, and is removed from its owner.
    /// </summary>
    void OnRemove();
}

/// <summary>
/// This interface is used to allow scripts to run before any hook is invoked. This allows for
/// suppressing certain categories of scripts, which can be useful for preventing certain effects
/// from running.
/// </summary>
public interface IScriptOnBeforeAnyHookInvoked
{
    /// <summary>
    /// This function is ran before any hook is invoked. This allows for suppressing certain categories
    /// of scripts. This is useful for example to prevent certain effects from running.
    /// </summary>
    void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories);
}

/// <summary>
/// This interface is used to allow scripts to run when they are initialized. This allows for
/// setting up the script with parameters that are passed to it.
/// </summary>
public interface IScriptOnInitialize
{
    /// <summary>
    /// This function is ran when the script is initialized. This allows for setting up the script
    /// with parameters that are passed to it.
    /// </summary>
    void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters);
}

/// <summary>
/// This interface is used to allow scripts to prevent a move from being selected.
/// </summary>
public interface IScriptPreventMoveSelection
{
    /// <summary>
    /// Override to customize whether the move can be selected at all.
    /// </summary>
    void PreventMoveSelection(IMoveChoice choice, ref bool prevent);
}

/// <summary>
/// This interface is used to allow scripts to force a certain turn choice to be selected.
/// </summary>
public interface IScriptForceTurnSelection
{
    /// <summary>
    /// Force a certain move choice to be selected. If the choice is set, the Pokemon will be forced
    /// to use it, and will not be able to select any other choice.
    /// </summary>
    void ForceTurnSelection(IBattle battle, byte sideIndex, byte position, ref ITurnChoice? choice);
}

/// <summary>
/// This interface is used to allow scripts to run before the start of a turn.
/// </summary>
public interface IScriptOnBeforeTurnStart
{
    /// <summary>
    /// This function is ran just before the start of the turn. Everyone has made its choices here,
    /// and the turn is about to start. This is a great place to initialize data if you need to know
    /// something has happened during a turn.
    /// </summary>
    void OnBeforeTurnStart(ITurnChoice choice);
}

/// <summary>
/// This interface allows scripts to modify the effective speed of the Pokemon.
/// </summary>
public interface IScriptChangeSpeed
{
    /// <summary>
    /// This function allows you to modify the effective speed of the Pokemon. This is run before
    /// turn ordering, so overriding here will allow you to put certain Pokemon before others.
    /// </summary>
    void ChangeSpeed(ITurnChoice choice, ref uint speed);
}

/// <summary>
/// This interface allows scripts to modify the effective priority of the Pokemon.
/// </summary>
public interface IScriptChangePriority
{
    /// <summary>
    /// This function allows you to modify the effective priority of the Pokemon. This is run before
    /// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
    /// that this is only relevant on move choices, as other turn choice types do not have a priority.
    /// </summary>
    void ChangePriority(IMoveChoice choice, ref sbyte priority);
}

/// <summary>
/// This interface allows scripts to change the move that is used during execution.
/// </summary>
public interface IScriptChangeMove
{
    /// <summary>
    /// This function allows you to change the move that is used during execution. This is useful for
    /// moves such as metronome, where the move chosen actually differs from the move used.
    /// </summary>
    void ChangeMove(IMoveChoice choice, ref StringKey moveName);
}

/// <summary>
/// This interface allows scripts to change the targets of a move choice.
/// </summary>
public interface IScriptChangeTargets
{
    /// <summary>
    /// Changes the targets of a move choice. This allows for changing the targets of a move before the move starts.
    /// </summary>
    void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets);
}

/// <summary>
/// This interface allows scripts to change the incoming targets of a move choice.
/// </summary>
public interface IScriptChangeIncomingTargets
{
    /// <summary>
    /// This function allows you to change the targets of a move choice before the move starts.
    /// </summary>
    void ChangeIncomingTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets);
}

/// <summary>
/// This interface allows scripts to change a move into a multi-hit move.
/// </summary>
public interface IScriptChangeNumberOfHits
{
    /// <summary>
    /// This function allows you to change a move into a multi-hit move. The number of hits set here
    /// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
    /// first hit.
    /// </summary>
    void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits);
}

/// <summary>
/// This interface allows scripts to prevent a move from running.
/// </summary>
public interface IScriptPreventMove
{
    /// <summary>
    /// This function allows you to prevent a move from running. If this gets set to true, the move
    /// ends execution here. No PP will be decreased in this case.
    /// </summary>
    void PreventMove(IExecutingMove move, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to make the move fail.
/// </summary>
public interface IScriptFailMove
{
    /// <summary>
    /// This function makes the move fail. If the fail field gets set to true, the move ends execution,
    /// and fail events get triggered.
    /// </summary>
    void FailMove(IExecutingMove move, ref bool fail);
}

/// <summary>
/// This interface allows scripts to stop execution of the move before it starts.
/// </summary>
public interface IScriptStopBeforeMove
{
    /// <summary>
    /// Similar to <see cref="IScriptPreventMove"/>. This function will also stop execution of the move, but
    /// PP will still be decreased.
    /// </summary>
    void StopBeforeMove(IExecutingMove move, ref bool stop);
}

/// <summary>
/// This interface allows scripts to run just before the move starts its execution.
/// </summary>
public interface IScriptOnBeforeMove
{
    /// <summary>
    /// This function runs just before the move starts its execution.
    /// </summary>
    void OnBeforeMove(IExecutingMove move);
}

/// <summary>
/// This interface allows scripts to run immediately after all targets have had their hits executed.
/// </summary>
public interface IScriptOnAfterMove
{
    /// <summary>
    /// This function runs immediately after all targets have had their hits executed.
    /// </summary>
    void OnAfterMove(IExecutingMove move);
}

/// <summary>
/// This interface allows scripts to change the type of a move that is used on a target.
/// </summary>
public interface IScriptChangeMoveType
{
    /// <summary>
    /// This function allows the script to change the actual type that is used for the move on a target.
    /// If this is set to null, the move will be treated as a typeless move.
    /// </summary>
    void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? typeIdentifier);
}

/// <summary>
/// This interface allows scripts to change the effectiveness of a move on a target.
/// </summary>
public interface IScriptChangeEffectiveness
{
    /// <summary>
    /// This function allows the script to change how effective a move is on a target.
    /// </summary>
    void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness);
}

/// <summary>
/// This interface allows scripts to change the effectiveness of a move on a target.
/// </summary>
public interface IScriptChangeIncomingEffectiveness
{
    /// <summary>
    /// This function allows the script to override how effective a move is on a target.
    /// </summary>
    void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
        ref float effectiveness);
}

/// <summary>
/// This interface allows scripts to block a critical hit from being applied to a move.
/// </summary>
public interface IScriptBlockCriticalHit
{
    /// <summary>
    /// This function allows a script to block an outgoing move from being critical.
    /// </summary>
    void BlockCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block);
}

/// <summary>
/// This interface allows scripts to block an incoming critical hit from being applied to a move.
/// </summary>
public interface IScriptBlockIncomingCriticalHit
{
    /// <summary>
    /// This function allows a script to block an incoming move from being critical.
    /// </summary>
    void BlockIncomingCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block);
}

/// <summary>
/// This interface allows scripts to run when an incoming hit happens.
/// </summary>
public interface IScriptOnIncomingHit
{
    /// <summary>
    /// This function triggers when an incoming hit happens. This triggers after the damage is done,
    /// but before the secondary effect of the move happens.
    /// </summary>
    void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit);
}

/// <summary>
/// This interface allows scripts to run when an opponent faints due to the move that is being executed.
/// </summary>
public interface IScriptOnOpponentFaints
{
    /// <summary>
    /// This function triggers when an opponent on the f ield faints due to the move that is being executed.
    /// </summary>
    void OnOpponentFaints(IExecutingMove move, IPokemon target, byte hit);
}

/// <summary>
/// This interface allows scripts to run when the move uses its secondary effect.
/// </summary>
public interface IScriptOnSecondaryEffect
{
    /// <summary>
    /// This function triggers when the move uses its secondary effect. Moves should implement their
    /// secondary effects here. Status moves should implement their actual functionality in this
    /// function as well, as status moves effects are defined as secondary effects for simplicity.
    /// </summary>
    void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit);
}

/// <summary>
/// This interface allows scripts to run when a move fails to hit its target.
/// </summary>
public interface IScriptFailIncomingMove
{
    /// <summary>
    /// This function allows a script to prevent a move that is targeted at its owner. If set to true
    /// the move fails, and fail events get triggered.
    /// </summary>
    void FailIncomingMove(IExecutingMove move, IPokemon target, ref bool fail);
}

/// <summary>
/// This interface allows scripts to run making the owner invulnerable to an incoming move.
/// </summary>
public interface IScriptIsInvulnerableToMove
{
    /// <summary>
    /// This function allows a script to make its owner invulnerable to an incoming move.
    /// </summary>
    void IsInvulnerableToMove(IExecutingMove move, IPokemon target, ref bool invulnerable);
}

/// <summary>
/// This interface allows scripts to run when a move misses its target.
/// </summary>
public interface IScriptOnMoveMiss
{
    /// <summary>
    /// This function allows a script to run when a move misses its target. This is used for moves
    /// that have a secondary effect that should run even if the move misses, such as Spore.
    /// </summary>
    void OnMoveMiss(IExecutingMove move, IPokemon target);
}

/// <summary>
/// This interface allows scripts to modify the accuracy modifier of a move.
/// </summary>
public interface IScriptChangeAccuracyModifier
{
    /// <summary>
    /// This function allows a script to modify the accuracy of a move used. This value represents
    /// the percentage accuracy, so anything above 100% will make it always hit.
    /// </summary>
    void ChangeAccuracyModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
}

/// <summary>
/// This interface allows scripts to change the critical stage of a move.
/// </summary>
public interface IScriptChangeCriticalStage
{
    /// <summary>
    /// This function allows a script to change the critical stage of the move used.
    /// </summary>
    void ChangeCriticalStage(IExecutingMove move, IPokemon target, byte hit, ref byte stage);
}

/// <summary>
/// This interface allows scripts to change the damage modifier of a critical hit.
/// </summary>
public interface IScriptChangeCriticalModifier
{
    /// <summary>
    /// This function allows a script to change the damage modifier of a critical hit. This will only
    /// run when a hit is critical.
    /// </summary>
    void ChangeCriticalModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
}

/// <summary>
/// This interface allows scripts to change the STAB (Same Type Attack Bonus) modifier.
/// </summary>
public interface IScriptChangeStabModifier
{
    /// <summary>
    /// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which
    /// occurs when the user has the move type as one of its own types.
    /// </summary>
    void ChangeStabModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber, bool isStab,
        ref float modifier);
}

/// <summary>
/// This interface allows scripts to change the effective base power of a move.
/// </summary>
public interface IScriptChangeBasePower
{
    /// <summary>
    /// This function allows a script to change the effective base power of a move hit.
    /// </summary>
    void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower);
}

/// <summary>
/// This interface allows scripts to bypass defensive stat boosts for a move hit.
/// </summary>
public interface IScriptBypassDefensiveStatBoosts
{
    /// <summary>
    /// This function allows a script to bypass defensive stat boosts for a move hit.
    /// If this is true, the damage will be calculated as if the target has no positive stat boosts. Negative
    /// stat boosts will still be applied.
    /// </summary>
    void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass);
}

/// <summary>
/// This interface allows scripts to bypass evasion stat boosts for a move hit.
/// </summary>
public interface IScriptBypassEvasionStatBoosts
{
    /// <summary>
    /// This function allows a script to bypass evasion stat boosts for a move hit.
    /// If this is true, the move will handle the evasion stat boosts as if the target has no positive stat boosts.
    /// </summary>
    void BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass);
}

/// <summary>
/// This interface allows scripts to bypass offensive stat boosts for a move hit.
/// </summary>
public interface IScriptBypassOffensiveStatBoosts
{
    /// <summary>
    /// This function allows a script to bypass offensive stat boosts for a move hit.
    /// If this is true, the damage will be calculated as if the user has no negative offensive stat boosts. Positive
    /// stat boosts will still be applied.
    /// </summary>
    void BypassOffensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass);
}

/// <summary>
/// This interface allows scripts to change the actual offensive stat values used when calculating damage.
/// </summary>
public interface IScriptChangeOffensiveStatValue
{
    /// <summary>
    /// This function allows a script to change the actual offensive stat values used when calculating damage
    /// </summary>
    void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
        ImmutableStatisticSet<uint> targetStats, Statistic stat, ref uint value);
}

/// <summary>
/// This interface allows scripts to change the actual defensive stat values used when calculating damage.
/// </summary>
public interface IScriptChangeDefensiveStatValue
{
    /// <summary>
    /// This function allows a script to change the actual defensive stat values used when calculating damage.
    /// </summary>
    void ChangeDefensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint offensiveStat,
        ImmutableStatisticSet<uint> targetStats, Statistic stat, ref uint value);
}

/// <summary>
/// This interface allows scripts to change the offensive stat value of an incoming move.
/// </summary>
public interface IScriptChangeIncomingMoveOffensiveStatValue
{
    /// <summary>
    /// This function allows a script to change the offensive stat value of an incoming move.
    /// </summary>
    void ChangeIncomingMoveOffensiveStatValue(IExecutingMove executingMove, IPokemon target, byte hitNumber,
        uint defensiveStat, StatisticSet<uint> targetStats, Statistic offensive, ref uint offensiveStat);
}

/// <summary>
/// This interface allows scripts to change the defensive stat value of an incoming move.
/// </summary>
public interface IScriptChangeIncomingMoveDefensiveStatValue
{
    /// <summary>
    /// This function allows a script to change the defensive stat value of an incoming move.
    /// </summary>
    void ChangeIncomingMoveDefensiveStatValue(IExecutingMove executingMove, IPokemon target, byte hitNumber,
        uint origOffensiveStat, StatisticSet<uint> targetStats, Statistic defensive, ref uint defensiveStat);
}

/// <summary>
/// This interface allows scripts to change the raw modifier retrieved from the stats of the defender and attacker.
/// </summary>
public interface IScriptChangeDamageStatModifier
{
    /// <summary>
    /// This function allows a script to change the raw modifier we retrieved from the stats of the
    /// defender and attacker. The default value is the offensive stat divided by the defensive stat.
    /// </summary>
    void ChangeDamageStatModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
}

/// <summary>
/// This interface allows scripts to apply a raw multiplier to the damage done by a move.
/// </summary>
public interface IScriptChangeDamageModifier
{
    /// <summary>
    /// This function allows a script to apply a raw multiplier to the damage done by a move.
    /// </summary>
    void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier);
}

/// <summary>
/// This interface allows scripts to change the damage modifier of an incoming move.
/// </summary>
public interface IScriptChangeIncomingMoveDamageModifier
{
    /// <summary>
    /// This function allows a script to change the damage modifier of an incoming move.
    /// </summary>
    void ChangeIncomingMoveDamageModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber,
        ref float modifier);
}

/// <summary>
/// This interface allows scripts to modify the outgoing damage done by a move.
/// </summary>
public interface IScriptChangeMoveDamage
{
    /// <summary>
    /// This function allows a script to modify the outgoing damage done by a move.
    /// </summary>
    void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage);
}

/// <summary>
/// This interface allows scripts to modify the incoming damage done by a move.
/// </summary>
public interface IScriptChangeIncomingMoveDamage
{
    /// <summary>
    /// This function allows a script to modify the incoming damage done by a move.
    /// </summary>
    void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage);
}

/// <summary>
/// This interface allows scripts attached to a Pokemon or its parents to prevent stat boost changes.
/// </summary>
public interface IScriptPreventStatBoostChange
{
    /// <summary>
    /// This function allows a script attached to a Pokemon or its parents to prevent stat boost
    /// changes on that Pokemon.
    /// </summary>
    void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted, ref bool prevent);
}

/// <summary>
/// This interface allows scripts attached to a Pokemon or its parents to modify stat boost changes.
/// </summary>
public interface IScriptChangeStatBoostChange
{
    /// <summary>
    /// This function allows a script attached to a Pokemon or its parents to modify the amount by
    /// which the stat boost will change. If the stat boost is done by the user itself, self
    /// inflicted will be true, otherwise it will be false.
    /// </summary>
    void ChangeStatBoostChange(IPokemon target, Statistic stat, bool selfInflicted, ref sbyte amount);
}

/// <summary>
/// This interface allows scripts to run after a stat boost change has been applied.
/// </summary>
public interface IScriptOnAfterStatBoostChange
{
    /// <summary>
    /// This function allows a script to run after a stat boost change has been applied.
    /// </summary>
    void OnAfterStatBoostChange(IPokemon pokemon, Statistic stat, bool selfInflicted, sbyte change);
}

/// <summary>
/// This interface allows scripts to prevent a secondary effect of a move from being applied.
/// </summary>
public interface IScriptPreventSecondaryEffect
{
    /// <summary>
    /// This function allows a script to prevent a secondary effect of a move from being applied.
    /// This means the move will still hit and do damage, but not trigger its secondary effect. Note that this
    /// function is not called for status moves.
    /// </summary>
    void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent);
}

/// <summary>
/// This interface allows scripts attached to a Pokemon or its parents to prevent incoming secondary effects.
/// </summary>
public interface IScriptPreventIncomingSecondaryEffect
{
    /// <summary>
    /// This function allows a script attached to a Pokemon or its parents to prevent an incoming
    /// secondary effect. This means the move will still hit and do damage, but not trigger its
    /// secondary effect. Note that this function is not called for status moves.
    /// </summary>
    void PreventIncomingSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent);
}

/// <summary>
/// This interface allows scripts attached to a move or its parents to change the chance of secondary effects.
/// </summary>
public interface IScriptChangeEffectChance
{
    /// <summary>
    /// This function allows a script attached to a move or its parents to change the chance the
    /// secondary effect of a move will trigger. The chance is depicted in percentage here, so
    /// changing this to above or equal to 100 will make it always hit, while setting it to equal or
    /// below 0 will make it never hit.
    /// </summary>
    void ChangeEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance);
}

/// <summary>
/// This interface allows scripts attached to a Pokemon or its parents to change the chance of incoming secondary effects.
/// </summary>
public interface IScriptChangeIncomingEffectChance
{
    /// <summary>
    /// This function allows a script attached to a Pokemon or its parents to change the chance the
    /// secondary effect of an incoming move will trigger. The chance is depicted in percentage here,
    /// so changing this to above or equal to 100 will make it always hit, while setting it to equal
    /// or below 0 will make it never hit.
    /// </summary>
    void ChangeIncomingEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance);
}

/// <summary>
/// This interface allows scripts to trigger when all hits on a target are finished.
/// </summary>
public interface IScriptOnAfterHits
{
    /// <summary>
    /// This function triggers on a move or its parents when all hits on a target are finished.
    /// </summary>
    void OnAfterHits(IExecutingMove move, IPokemon target);
}

/// <summary>
/// This interface allows scripts to trigger at the end of each turn.
/// </summary>
public interface IScriptOnEndTurn
{
    /// <summary>
    /// This function id triggered on all scripts active in the battle after all choices have finished
    /// running. Note that choices are not active anymore here, so their scripts do not call this
    /// function.
    /// </summary>
    void OnEndTurn(IScriptSource owner, IBattle battle);
}

/// <summary>
/// This interface allows scripts to prevent the Pokemon it is attached to from being able to switch out.
/// </summary>
public interface IScriptPreventSelfSwitch
{
    /// <summary>
    /// This function prevents the Pokemon it is attached to from being able to switch out.
    /// </summary>
    void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to prevent switching for any opponent.
/// </summary>
public interface IScriptPreventOpponentSwitch
{
    /// <summary>
    /// This function allows the prevention of switching for any opponent.
    /// </summary>
    void PreventOpponentSwitch(ISwitchChoice choice, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to prevent the Pokemon its attached to from running away.
/// </summary>
public interface IScriptPreventSelfRunAway
{
    /// <summary>
    /// This function allows preventing the running away of the Pokemon its attached to
    /// </summary>
    void PreventSelfRunAway(IFleeChoice choice, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to prevent a Pokemon on another side from running away.
/// </summary>
public interface IScriptPreventOpponentRunAway
{
    /// <summary>
    /// This function prevents a Pokemon on another side than where its attached to from running away.
    /// </summary>
    void PreventOpponentRunAway(IFleeChoice choice, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to trigger when a Pokemon takes damage.
/// </summary>
public interface IScriptOnDamage
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
    /// </summary>
    void OnDamage(IPokemon pokemon, DamageSource source, uint oldHealth, uint newHealth);
}

/// <summary>
/// This interface allows scripts to trigger when a Pokemon faints.
/// </summary>
public interface IScriptOnFaint
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
    /// </summary>
    void OnFaint(IPokemon pokemon, DamageSource source);
}

/// <summary>
/// This interface allows scripts to trigger when an ally Pokemon faints.
/// </summary>
public interface IScriptOnAllyFaint
{
    /// <summary>
    /// This function is triggered on a Pokemon when an ally Pokemon faints.
    /// </summary>
    void OnAllyFaint(IPokemon ally, IPokemon faintedPokemon);
}

/// <summary>
/// This interface allows scripts to trigger when a Pokemon switches out of the battlefield.
/// </summary>
public interface IScriptOnSwitchOut
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon switches out
    /// of the battlefield.
    /// </summary>
    void OnSwitchOut(IPokemon oldPokemon, byte position);
}

/// <summary>
/// This interface allows scripts to trigger when a Pokemon is switched into the battlefield.
/// </summary>
public interface IScriptOnSwitchIn
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
    /// the battlefield.
    /// </summary>
    void OnSwitchIn(IPokemon pokemon, byte position);
}

/// <summary>
/// This interface allows scripts to trigger when an opponent Pokemon switches in.
/// </summary>
public interface IScriptOnOpponentSwitchIn
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when an opponent switches in.
    /// </summary>
    void OnOpponentSwitchIn(IPokemon pokemon, byte position);
}

/// <summary>
/// This interface allows scripts to stack when a volatile effect is added while already in place.
/// </summary>
public interface IScriptStack
{
    /// <summary>
    /// This function is ran when a volatile effect is added while that volatile effect already is
    /// in place. Instead of adding the volatile effect twice, it will execute this function instead.
    /// </summary>
    void Stack();
}

/// <summary>
/// This interface allows scripts to trigger after a Pokemon consumes an item.
/// </summary>
public interface IScriptOnAfterItemConsume
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
    /// held item it had.
    /// </summary>
    void OnAfterItemConsume(IPokemon pokemon, IItem item);
}

/// <summary>
/// This interface allows scripts to block incoming hits on a target.
/// </summary>
public interface IScriptBlockIncomingHit
{
    /// <summary>
    /// This function allows a script to block an incoming hit.
    /// </summary>
    void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block);
}

/// <summary>
/// This interface allows scripts to block outgoing hits from a move.
/// </summary>
public interface IScriptBlockOutgoingHit
{
    /// <summary>
    /// This function allows a script to block an outgoing hit.
    /// </summary>
    void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block);
}

/// <summary>
/// This interface allows scripts to prevent held item consumption.
/// </summary>
public interface IScriptPreventHeldItemConsume
{
    /// <summary>
    /// This function allows a script to prevent a held item from being consumed.
    /// </summary>
    void PreventHeldItemConsume(IPokemon pokemon, IItem heldItem, ref bool prevented);
}

/// <summary>
/// This interface allows scripts to change incoming damage to a Pokemon.
/// </summary>
public interface IScriptChangeIncomingDamage
{
    /// <summary>
    /// This function allows a script to change any kind of damage that is incoming.
    /// </summary>
    void ChangeIncomingDamage(IPokemon pokemon, DamageSource source, ref uint damage);
}

/// <summary>
/// This interface allows scripts to change the weather duration of a weather effect.
/// </summary>
public interface IScriptChangeWeatherDuration
{
    /// <summary>
    /// This function allows a script to change the weather duration of a weather effect.
    /// </summary>
    void ChangeWeatherDuration(StringKey weatherName, ref int duration);
}

/// <summary>
/// This interface allows scripts to prevent a Pokemon from being healed.
/// </summary>
public interface IScriptPreventHeal
{
    /// <summary>
    /// This function allows a script to prevent a Pokemon from being healed.
    /// </summary>
    void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented);
}

/// <summary>
/// This interface allows scripts to change the types a target has for effectiveness calculation.
/// </summary>
public interface IScriptChangeTypesForMove
{
    /// <summary>
    /// This function allows a script to change the types a target has. Multiple types can be set, and will be used
    /// for the effectiveness calculation.
    /// </summary>
    void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex, IList<TypeIdentifier> types);
}

/// <summary>
/// This interface allows scripts to change the types a Pokemon has for incoming moves.
/// </summary>
public interface IScriptChangeTypesForIncomingMove
{
    /// <summary>
    /// This function allows a script to change the types a Pokemon has for a move that's incoming. Multiple types can
    /// be set, and will be used for the effectiveness calculation.
    /// </summary>
    void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
        IList<TypeIdentifier> types);
}

/// <summary>
/// This interface allows scripts to change the handling of the move category.
/// </summary>
public interface IScriptChangeCategory
{
    /// <summary>
    /// This function allows a script to change the handling of the move category. This is used for moves that
    /// are sometimes a status move, and sometimes a damaging move, such as pollen puff.
    /// </summary>
    void ChangeCategory(IExecutingMove move, IPokemon target, byte hitIndex, ref MoveCategory category);
}

/// <summary>
/// This interface allows scripts to trigger when about to hit a target.
/// </summary>
public interface IScriptOnBeforeHit
{
    /// <summary>
    /// Triggers first when we're about to hit a target.
    /// </summary>
    void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex);
}

/// <summary>
/// This interface allows scripts to prevent a Pokemon from being affected by a status condition.
/// </summary>
public interface IScriptPreventStatusChange
{
    /// <summary>
    /// This function allows a script to prevent a Pokemon from being affected by a status condition.
    /// </summary>
    void PreventStatusChange(IPokemon pokemon, StringKey status, bool selfInflicted, ref bool preventStatus);
}

/// <summary>
/// This interface allows scripts to trigger after a status condition has been applied.
/// </summary>
public interface IScriptOnAfterStatusChange
{
    /// <summary>
    /// This function triggers after a status condition has been applied to a Pokemon.
    /// </summary>
    void OnAfterStatusChange(IPokemon pokemon, StringKey status, IPokemon? originPokemon);
}

/// <summary>
/// This interface allows scripts to prevent a Pokemon from being affected by a volatile status condition.
/// </summary>
public interface IScriptPreventVolatileAdd
{
    /// <summary>
    /// This function allows a script to prevent a Pokémon from being affected by a volatile status condition.
    /// </summary>
    void PreventVolatileAdd(IScriptSource parent, Script script, ref bool preventVolatileAdd);
}

/// <summary>
/// This interface allows scripts to make the Pokemon float.
/// </summary>
public interface IScriptIsFloating
{
    /// <summary>
    /// This function allows a script to make the Pokémon it is attached to float. This is used for moves
    /// such as levitate, and allows for moves such as earthquake to not hit the Pokémon.
    /// </summary>
    void IsFloating(IPokemon pokemon, ref bool isFloating);
}

/// <summary>
/// This interface allows scripts to prevent weather from changing.
/// </summary>
public interface IScriptPreventWeatherChange
{
    /// <summary>
    /// This function allows a script to prevent the weather from changing. This is used for abilities such as
    /// Delta Stream, which prevent the weather from changing to anything other than strong winds.
    /// </summary>
    void PreventWeatherChange(StringKey? weatherName, ref bool preventWeatherChange);
}

/// <summary>
/// This interface allows scripts to trigger when the weather changes.
/// </summary>
public interface IScriptOnWeatherChange
{
    /// <summary>
    /// This function triggers when the weather changes.
    /// </summary>
    void OnWeatherChange(IBattle battle, StringKey? weatherName, StringKey? oldWeatherName);
}

/// <summary>
/// This interface allows scripts to modify the weight of a Pokemon.
/// </summary>
public interface IScriptModifyWeight
{
    /// <summary>
    /// Modifies the weight of a Pokemon.
    /// </summary>
    void ModifyWeight(ref float weight);
}

/// <summary>
/// This interface allows scripts to modify whether a move makes contact.
/// </summary>
public interface IScriptModifyIsContact
{
    /// <summary>
    /// Modifies whether a move is a contact move or not. This is used for abilities such as Long Reach.
    /// </summary>
    void ModifyIsContact(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool isContact);
}

/// <summary>
/// This interface allows scripts to prevent held item theft.
/// </summary>
public interface IScriptPreventHeldItemSteal
{
    /// <summary>
    /// This function allows a script to prevent a held item from being stolen by an effect such as Thief or Covet.
    /// </summary>
    void PreventHeldItemSteal(IPokemon pokemon, IItem heldItem, ref bool prevent);
}

/// <summary>
/// This interface allows scripts to trigger after held item changes.
/// </summary>
public interface IScriptOnAfterHeldItemChange
{
    /// <summary>
    /// This function allows a script to run after a held item has changed.
    /// </summary>
    void OnAfterHeldItemChange(IPokemon pokemon, IItem? previous, IItem? item);
}

/// <summary>
/// This interface allows scripts to modify the PP used by a move.
/// </summary>
public interface IScriptModifyPPUsed
{
    /// <summary>
    /// This function allows a script to modify the PP used by a move.
    /// </summary>
    void ModifyPPUsed(IExecutingMove executingMove, ref byte ppUsed);
}

/// <summary>
/// This interface allows scripts to modify the PP used by an incoming move.
/// </summary>
public interface IScriptModifyPPUsedForIncomingMove
{
    /// <summary>
    /// This function allows a script to modify the PP used by an incoming move. This is used for abilities such as Pressure.
    /// </summary>
    void ModifyPPUsedForIncomingMove(IExecutingMove executingMove, ref byte ppUsed);
}

/// <summary>
/// This interface allows scripts to trigger just before a move choice is executed.
/// </summary>
public interface IScriptOnBeforeMoveChoice
{
    /// <summary>
    /// This function triggers just before a move choice is executed.
    /// </summary>
    void OnBeforeMoveChoice(IMoveChoice moveChoice);
}

/// <summary>
/// This interface allows scripts to trigger after a move choice has been executed.
/// </summary>
public interface IScriptOnAfterMoveChoice
{
    /// <summary>
    /// This function triggers after a move choice has been executed in its entirety.
    /// </summary>
    void OnAfterMoveChoice(IMoveChoice moveChoice);
}

/// <summary>
/// This interface allows scripts to change the turn choice that is made by a Pokemon.
/// </summary>
public interface IScriptChangeTurnChoice
{
    /// <summary>
    /// This function allows a script to change the turn choice that is made by a Pokemon.
    /// </summary>
    void ChangeTurnChoice(ref ITurnChoice choice);
}

/// <summary>
/// This interface allows scripts to change the experience gained when a Pokemon faints.
/// </summary>
public interface IScriptChangeExperienceGained
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
    /// and allows for changing this amount of experience.
    /// </summary>
    void ChangeExperienceGained(IPokemon faintedPokemon, IPokemon winningPokemon, ref uint amount);
}

/// <summary>
/// This interface allows scripts to share experience across multiple Pokemon.
/// </summary>
public interface IScriptShareExperience
{
    /// <summary>
    /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
    /// and allows for making the experience be shared across multiple Pokemon.
    /// Amount is the modifier for how much experience is shared, with 1 being the default amount.
    /// </summary>
    void ShareExperience(IPokemon faintedPokemon, IPokemon winningPokemon, ref bool share, ref float amount);
}

/// <summary>
/// This interface allows scripts to block weather changes.
/// </summary>
public interface IScriptBlockWeatherChange
{
    /// <summary>
    /// This function allows a script to block weather changes.
    /// </summary>
    void BlockWeatherChange(IBattle battle, ref bool block);
}

/// <summary>
/// This interface allows scripts to change the catch rate bonus when a Pokeball is thrown.
/// </summary>
public interface IScriptChangeCatchRateBonus
{
    /// <summary>
    /// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
    /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
    /// example status effects that change capture rates.
    /// </summary>
    void ChangeCatchRateBonus(IPokemon pokemon, IItem pokeball, ref byte modifier);
}

/// <summary>
/// This interface allows scripts to handle custom trigger events.
/// </summary>
public interface IScriptCustomTrigger
{
    /// <summary>
    /// Custom triggers for scripts. This allows scripts to run custom events that are not part of the
    /// standard battle flow.
    /// </summary>
    void CustomTrigger(StringKey eventName, ICustomTriggerArgs args);
}

/// <summary>
/// This interface allows scripts to change the accuracy of a move.
/// </summary>
public interface IScriptChangeAccuracy
{
    /// <summary>
    /// This function allows a script to change the accuracy of a move used. The value for accuracy is in percentage.
    /// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move
    /// will always hit.
    /// </summary>
    void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy);
}

/// <summary>
/// This interface allows scripts to change the accuracy of an incoming move.
/// </summary>
public interface IScriptChangeIncomingAccuracy
{
    /// <summary>
    /// This function allows a script to change the accuracy of a move that is incoming. The value for accuracy is in percentage.
    /// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move
    /// will always hit.
    /// </summary>
    void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy);
}