import enum
from event_testing.tests import TunableTestSet
from postures import PostureTrack
from routing.portals.portal_tuning import PortalFlags
from sims.sim_info_types import SpeciesExtended
from sims4.tuning.tunable import TunableReference, TunableTuple, TunableMapping, TunableEnumEntry, TunableList, TunablePackSafeReference, Tunable, TunableRange, OptionalTunable, TunableEnumFlags
import services
import sims4.resources
from sims4.tuning.tunable_hash import TunableStringHash32
from tunable_multiplier import TestedSum

class CarryPostureStaticTuning:
    POSTURE_CARRY_NOTHING = TunableReference(description='\n            Reference to the posture that represents carrying nothing\n            ', manager=services.get_instance_manager(sims4.resources.Types.POSTURE), class_restrictions='CarryingNothing')
    POSTURE_CARRY_OBJECT = TunableReference(description='\n        Reference to the posture that represents carrying an Object\n        ', manager=services.get_instance_manager(sims4.resources.Types.POSTURE), class_restrictions='CarryingObject')


class CarryTuning:
    RALLY_INTERACTION_CARRY_RULES = TunableTuple(description='\n        Global rules related to carry while running rally interactions.\n        ', min_carry_distance=Tunable(description="\n            Only initiate carry if the carryable sim's route distance is larger than this min distance. \n            ", tunable_type=float, default=1), wait_to_carry_affordance=TunableReference(description='\n            The affordance to push to a carrying sim while they are waiting the carryable sim to drag them into carry.\n            This affordance is just for the player UI feedback purpose, should do nothing but show an icon in the\n            interaction queue indicating the sim is doing something.\n            ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION)))
    CARRY_PATH_CONSTRAINT_RULES = TunableTuple(description='\n        Global rules related to Carry Path Constraint.\n        ', min_carry_distance=Tunable(description="\n            Only initiate carry if the carryable sim's route distance is larger than this min distance. \n            ", tunable_type=float, default=1))
    CARRYABLE_SIMS_FIXUP_RULES = TunableTuple(description="\n        Fixup rules for carryable sims in different scenarios (such as after travel, moving into a lot, being adopted)\n        We use these rules to carry sims (especially infants) immediately in those scenarios so they won't look bad\n        laying on the ground. Note that this takes higher precedence than PERSIST_CARRIED_SIMS_FIXUP_RULES, which is \n        only used so that sims that were already being carried look like they're being carried by the same carriers \n        after travel.\n        ", carry_hand_affordance_mappings=TunableMapping(description='\n            A mapping of carry hand to carry rules. Usually each hand can carry one carryable sim.\n            ', key_type=TunableEnumEntry(description="\n                The carrying sim's carry hand.\n                ", tunable_type=PostureTrack, default=PostureTrack.RIGHT), value_type=TunableList(description='\n                Carry owning affordances and corresponding joint for the carry hand.\n                ', tunable=TunableTuple(owning_affordance=TunablePackSafeReference(description='\n                        The affordance to push a Sim to carry the carryable sim. We run \n                        affordance tests against the carryable sim, if all affordances \n                        in the list fails we will skip that sim and try the next carryable sim.\n                        ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION)), parenting_joint=TunableStringHash32(description='\n                        The joint of the carrier sim to parent the carryable sim to.\n                        '), parenting_joint_pet=TunableStringHash32(description='\n                        The joint of the carrier sim to parent the carryable pet to.\n                        ')))), priority_test_sums=TestedSum.TunableFactory(description='\n            Tested sums to create a priority list for carryable sims. We will try to carry sims\n            who has highest scores first.\n            '), carryable_sim_eligibility_tests=TunableTestSet(description='\n            Tunable tests that run on carryable sims to check if we should carry \n            them at all.\n            '), carrying_sim_eligibility_tests=TunableTestSet(description='\n            Tunable tests that run on carrying sims to check eligibility for\n            carrying any sim.\n            '))
    MAXIMUM_PUTDOWN_DERAILMENT = TunableRange(description="\n        The maximum putdown derailment request for each interaction.\n        An interaction will request putdown derailment to wait for the carried sim to be putdown somewwhere.\n        After the initial putdown, the interaction may keep requesting putdown derailment if the new location\n        still doesn't satisfy the constraint (either due to bugs or as designed). To prevent them from getting\n        into this pickup-putdown loop, we added this constant to restrict the maximum derailment request.\n        ", tunable_type=int, default=1, minimum=1)
    PUTDOWN_DERAILMENT_INTERACTION_MAP = TunableMapping(description='\n        Mapping of specific interactions to a maximum putdown derailment request count.\n        The values tuned here will override the MAXIMUM_PUTDOWN_DERAILMENT tuned value \n        ONLY for the interactions tuned here.\n        ', key_type=TunablePackSafeReference(description='\n            The interaction requesting putdown derailments.\n            ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION)), value_type=TunableRange(description='\n            The maximum putdown derailment request count for this interaction.\n            ', tunable_type=int, default=1, minimum=1))
    CARRIED_SIM_PROXY_AFFORDANCE = TunableReference(description='\n        The CarriedSimProxyInteraction a carried sim plays when a carrier\n        requests them via link_carried_sims in a paired interaction. Used\n        to link the carrier and carried sim so that cancelling either the\n        original interaction or the proxy will cancel the other, and\n        otherwise last for an equivalent lifetime.\n        ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION))
    HORSE_SATISFY_CONSTRAINTS_INTERACTION = TunablePackSafeReference(description='\n        The HorseSatisfyConstraintSuperInteraction is used by the transition\n        sequence to route a horse closer before attempting to dismount in the \n        event that dismount is no longer required after routing.\n        ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION))
    PERSIST_CARRIED_SIMS_FIXUP_RULES = TunableMapping(description="\n        Mapping of species to fixup rules for persisting certain carried sims \n        after travel. Used to match carried sims to their carriers so that \n        they look like they've been carried through travel. Note that this\n        takes lower precedence than CARRYABLE_SIMS_FIXUP_RULES, which attaches\n        carryable sims to carriers regardless of whether they were being carried\n        before travel.\n        ", key_name='species', key_type=TunableEnumEntry(description='\n            The extended species that these rules run for.\n            ', tunable_type=SpeciesExtended, default=SpeciesExtended.HUMAN), value_name='carry_rules', value_type=TunableTuple(eligibility_tests=TunableTestSet(description='\n                Tunable tests that run on carrying sims to check eligibility for\n                persisting carry after travel. If passed, will try to restore their\n                current carrying state after travel.\n                '), owning_affordance=TunablePackSafeReference(description='\n                The affordance to push a Sim to carry the carryable sim. This is a\n                direct species mapping for now, and is limited to carrying one sim\n                on the specified carry track hand.\n                ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION)), carry_track_hand=TunableEnumEntry(description="\n                The carrying sim's carry hand.\n                ", tunable_type=PostureTrack, default=PostureTrack.RIGHT), parenting_joint=TunableStringHash32(description='\n                The joint of the carrier sim to parent the carryable sim to.\n                ')))
    FAIRY_SIM_CARRYING_PORTAL_FLAGS = TunableTuple(description="\n        Override PortalFlags bits on a fairy Sim's routing context\n        when the fairy Sim is carrying another Sim.\n        ", apply_to_back_carries=Tunable(description='\n            If true, the Fairy Sim Carrying Portal Flags tuning\n            will apply to fairies performing back carries with\n            another Sim. Not affected by object carries.\n            ', tunable_type=bool, default=False), apply_to_front_carries=Tunable(description='\n            If true, the Fairy Sim Carrying Portal Flags tuning\n            will apply to fairies performing front carries with\n            another Sim. Not affected by object carries.\n            ', tunable_type=bool, default=False), flying_walkstyle_trait=TunablePackSafeReference(description='\n            Only fairy Sims with this walkstyle trait will\n            have their portal flags changed by this tuning.\n            ', manager=services.get_instance_manager(sims4.resources.Types.TRAIT), class_restrictions=('Trait',)), set_flags=OptionalTunable(TunableTuple(description="\n                Tuple of allowance, discouragement, and exclusion flags that will be set\n                on the fairy Sim's routing context for the duration of the carry posture.\n                ", portal_allowance_flags=TunableEnumFlags(description="\n                    Bits tuned here will be set on the fairy Sim's\n                    allowed portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be unset.\n                    \n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True), portal_discouragement_flags=TunableEnumFlags(description="\n                    Bits tuned here will be set on the fairy Sim's\n                    discouragement portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be unset.\n                    \n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True), portal_exclusion_flags=TunableEnumFlags(description="\n                    Bits tuned here will be set on the fairy Sim's\n                    exclusion portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be unset.\n\n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True))), unset_flags=OptionalTunable(TunableTuple(description="\n                Tuple of allowance, discouragement, and exclusion flags to be removed \n                from the fairy Sim's routing context for the duration of the carry posture.\n                ", portal_allowance_flags=TunableEnumFlags(description="\n                    Bits tuned here will be unset on the fairy Sim's\n                    allowed portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be set.\n                    \n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True), portal_discouragement_flags=TunableEnumFlags(description="\n                    Bits tuned here will be unset on the fairy Sim's\n                    discouragement portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be set.\n                    \n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True), portal_exclusion_flags=TunableEnumFlags(description="\n                    Bits tuned here will be unset on the fairy Sim's\n                    exclusion portal flags. When the fairy Sim is no longer\n                    carrying another Sim, the tuned bits will be set.\n\n                    NOTE: This functionality does not care what the existing \n                    value of the bits are, and this will do exactly what it \n                    says, overwriting any previous value.\n                    ", enum_type=PortalFlags, allow_no_flags=True))))


class CarryTransitionState(enum.Int):
    NOT_STARTED = 0
    WAITING = 1
    FINISHED = 2
    LOCKED = 3

