using System;
using ModernUO.Serialization;
using Server.Engines.Craft;
using Server.Network;

namespace Server.Items;

[SerializationGenerator(0, false)]
public abstract partial class LockableContainer : TrappableContainer, ILockable, ILockpickable, ICraftable, IShipwreckedItem
{
    public LockableContainer(int itemID) : base(itemID) => MaxLockLevel = 100;

    public override bool TrapOnOpen => !_trapOnLockpick;

    public override bool DisplaysContent => !_locked;

    public int OnCraft(
        int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool,
        CraftItem craftItem, int resHue
    )
    {
        if (from.CheckSkill(SkillName.Tinkering, -5.0, 15.0))
        {
            from.SendLocalizedMessage(500636); // Your tinker skill was sufficient to make the item lockable.

            var key = new Key(KeyType.Copper, Key.RandomValue());

            _keyValue = key.KeyValue;
            DropItem(key);

            var tinkering = from.Skills.Tinkering.Value;
            var level = (int)(tinkering * 0.8);

            _requiredSkill = Math.Min(level - 4, 95);
            _maxLockLevel = Math.Min(level + 35, 95);

            // Lock level of 0 means it is not pickable, so change it to -1
            _lockLevel = level == 14 ? -1 : Math.Min(level - 14, 95);
        }
        else
        {
            from.SendLocalizedMessage(500637); // Your tinker skill was insufficient to make the item lockable.
        }

        return 1;
    }

    [CommandProperty(AccessLevel.GameMaster)]
    public Mobile Picker { get; set; }

    [SerializableField(0)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private bool _isShipwreckedItem;

    [SerializableField(1)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private bool _trapOnLockpick;

    [SerializableField(2)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private int _requiredSkill;

    [SerializableField(3)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private int _maxLockLevel;

    [SerializableField(4)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private uint _keyValue;

    [SerializableField(5)]
    [SerializedCommandProperty(AccessLevel.GameMaster)]
    private int _lockLevel;

    [SerializableProperty(6)]
    [CommandProperty(AccessLevel.GameMaster)]
    public virtual bool Locked
    {
        get => _locked;
        set
        {
            _locked = value;

            if (_locked)
            {
                Picker = null;
            }

            InvalidateProperties();
            this.MarkDirty();
        }
    }

    public virtual void LockPick(Mobile from)
    {
        Locked = false;
        Picker = from;

        if (_trapOnLockpick && ExecuteTrap(from))
        {
            _trapOnLockpick = false;
        }
    }

    public override bool CheckContentDisplay(Mobile from) => !_locked && base.CheckContentDisplay(from);

    public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage)
    {
        if (from.AccessLevel < AccessLevel.GameMaster && _locked)
        {
            from.SendLocalizedMessage(501747); // It appears to be locked.
            return false;
        }

        return base.TryDropItem(from, dropped, sendFullMessage);
    }

    public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
    {
        if (from.AccessLevel < AccessLevel.GameMaster && _locked)
        {
            from.SendLocalizedMessage(501747); // It appears to be locked.
            return false;
        }

        return base.OnDragDropInto(from, item, p);
    }

    public override bool CheckLift(Mobile from, Item item, ref LRReason reject) =>
        base.CheckLift(from, item, ref reject) &&
        (item == this || from.AccessLevel >= AccessLevel.GameMaster || !_locked);

    public override bool CheckItemUse(Mobile from, Item item)
    {
        if (!base.CheckItemUse(from, item))
        {
            return false;
        }

        if (item != this && from.AccessLevel < AccessLevel.GameMaster && _locked)
        {
            from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
            return false;
        }

        return true;
    }

    public virtual bool CheckLocked(Mobile from)
    {
        if (!_locked)
        {
            return false;
        }

        var inaccessible = from.AccessLevel < AccessLevel.GameMaster;

        int number = inaccessible
            ? 501747 // It appears to be locked.
            : 502502;    // That is locked, but you open it with your godly powers.

        from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number);

        return inaccessible;
    }

    public override void OnTelekinesis(Mobile from)
    {
        if (CheckLocked(from))
        {
            Effects.SendLocationParticles(
                EffectItem.Create(Location, Map, EffectItem.DefaultDuration),
                0x376A,
                9,
                32,
                5022
            );
            Effects.PlaySound(Location, Map, 0x1F5);
            return;
        }

        base.OnTelekinesis(from);
    }

    public override void OnDoubleClickSecureTrade(Mobile from)
    {
        if (CheckLocked(from))
        {
            return;
        }

        base.OnDoubleClickSecureTrade(from);
    }

    public override void Open(Mobile from)
    {
        if (CheckLocked(from))
        {
            return;
        }

        base.Open(from);
    }

    public override void OnSnoop(Mobile from)
    {
        if (CheckLocked(from))
        {
            return;
        }

        base.OnSnoop(from);
    }

    public override void AddNameProperties(IPropertyList list)
    {
        base.AddNameProperties(list);

        if (_isShipwreckedItem)
        {
            list.Add(1041645); // recovered from a shipwreck
        }
    }

    public override void OnSingleClick(Mobile from)
    {
        base.OnSingleClick(from);

        if (_isShipwreckedItem)
        {
            LabelTo(from, 1041645); // recovered from a shipwreck
        }
    }
}
