using System;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Objects.Unit.Actions;
using VOID.Generic.Player.Input;
using VOID.Generic.Player.Util;
using VOID.UserInterface.Game;
using VOID.Generic.Util;

namespace VOID.Generic.Player.CursorOperation
{
    public class OnUnitCursorOperation : AbstractCursorOperation
    {
        public override Type ForType() => typeof(UnitObject);

        public override bool Check(SelectUtilResult select)
        {
            return select.selectObject is UnitObject;
        }

        public override void DoDefault(SelectUtilResult select, bool isAlternate)
        {
            var onPartyUI = select.partyUI != null;
            var onPortraitUI = select.unitPortraitUI != null;
            var activeUnit = PlayerController.current.activeUnit;
            var attackAbility = activeUnit.unitAbilityBook.attackAbility;
            var targetUnit = (UnitObject)select.selectObject;
            var attitude = activeUnit.unitAttitude.GetAttitudeWith(targetUnit);

            if (isAlternate && onPortraitUI && onPartyUI && targetUnit == PlayerController.current.activeUnit)
            {
                CameraManager.current.MoveTo(targetUnit.transform.position);
            }
            else if (isAlternate && onPortraitUI && onPartyUI && targetUnit == PlayerController.current.mainUnit)
            {
                PlayerController.current.SetMainUnitActive();
            }
            else if (isAlternate && onPortraitUI && onPartyUI && targetUnit == PlayerController.current.subUnit)
            {
                PlayerController.current.SetSubUnitActive();
            }
            else if (isAlternate && onPortraitUI)
            {
                CameraManager.current.MoveTo(targetUnit.transform.position);
            }
            else if (!isAlternate && onPortraitUI)
            {
                CameraManager.current.stickTo = targetUnit.transform;
            }

            // No action to order when clicking portraits
            if (onPortraitUI) return;

            activeUnit.OrderStop();

            if (targetUnit.basicState.isDead)
            {
                // Open - when other unit is dead, we open him like container
                activeUnit.Order(new MoveAction(activeUnit, targetUnit, activeUnit.unitData.takeRange));
                activeUnit.Order(new OpenOtherUnitAction(activeUnit, targetUnit));
            }
            else if (activeUnit.unitData.canAttack && (PlayerInputManager.current.isForceAttack || attitude <= AttitudeType.Cautious))
            {
                // Attack - when this unit can Attack AND forced attack OR target unit is hostile/cautious
                activeUnit.Order(new MoveAction(activeUnit, select.position, attackAbility.range));
                activeUnit.Order(new AbilityAction(activeUnit, attackAbility, select.position));
            }
            else
            {
                // Talk - when this unit can Talk AND target unit is neutral/friendly
                activeUnit.Order(new MoveAction(activeUnit, targetUnit, activeUnit.unitData.talkRange));
                if (activeUnit.unitData.canTalk && targetUnit.unitData.canBeTalked) activeUnit.Order(new TalkAction(activeUnit, targetUnit));
            }
        }

        public override void DoContext(SelectUtilResult select)
        {
            var activeUnit = PlayerController.current.activeUnit;
            var attackAbility = activeUnit.unitAbilityBook.attackAbility;
            var targetUnit = (UnitObject)select.selectObject;
            var attitude = activeUnit.unitAttitude.GetAttitudeWith(targetUnit);

            if (targetUnit == activeUnit && select.onUI) return;

            ContextMenuUI.current.Prepare();
            
            ContextMenuUI.current.AddBeforeClick(() => activeUnit.OrderStop());

            if (activeUnit.unitData.canMove)
            {
                ContextMenuUI.current.AddOption("Move",
                    () => activeUnit.Order(new MoveAction(activeUnit, select.position)));
            }
            if (targetUnit.basicState.isDead)
            {
                ContextMenuUI.current.AddOption("Loot", () =>
                {
                    activeUnit.Order(new MoveAction(activeUnit, targetUnit, activeUnit.unitData.takeRange));
                    activeUnit.Order(new OpenOtherUnitAction(activeUnit, targetUnit));
                });
            }
            if (activeUnit.unitData.canAttack)
            {
                ContextMenuUI.current.AddOption("Attack", () =>
                {
                    activeUnit.Order(new MoveAction(activeUnit, select.position, attackAbility.range));
                    activeUnit.Order(new AbilityAction(activeUnit, attackAbility, select.position));
                });
            }
            if (attitude >= AttitudeType.Neutral && activeUnit.unitData.canTalk && targetUnit.unitData.canBeTalked)
            {
                ContextMenuUI.current.AddOption("Talk", () =>
                {
                    activeUnit.Order(new MoveAction(activeUnit, select.position, activeUnit.unitData.takeRange));
                    activeUnit.Order(new TalkAction(activeUnit, targetUnit));
                });
            }
            if (activeUnit.unitData.canInspect && targetUnit.basicData.canBeInspected)
            {
                ContextMenuUI.current.AddOption("Inspect", () =>
                {
                    MoveAction moveAction = new MoveAction(activeUnit, select.position, activeUnit.unitData.inspectRange);
                    moveAction.OnEnd += () => activeUnit.OrderInstantly(new InspectAction(activeUnit, targetUnit));
                    activeUnit.Order(moveAction);
                });
            }
            ContextMenuUI.current.Open();
        }
    }
}