using System;
using System.Runtime.InteropServices;
using Decal.Interop.Core;

namespace Decal.Core
{
    [ComVisible(true)]
    [Guid("CB8875CD-ABC2-42AD-8175-8908706EED37")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces("Decal.Interop.Core.IACHooksEvents\0\0")]
    [ProgId("Decal.ACHooks")]
    public class ACHooksImpl : IACHooks
    {
        // COM events
        public event IACHooksEvents_ObjectDestroyedEventHandler ObjectDestroyed;
        public event IACHooksEvents_ChatTextInterceptEventHandler ChatTextIntercept;
        public event IACHooksEvents_ChatParserInterceptEventHandler ChatParserIntercept;
        public event IACHooksEvents_StatusTextInterceptEventHandler StatusTextIntercept;
        public event IACHooksEvents_ObjectSelectedEventHandler ObjectSelected;
        public event IACHooksEvents_MessageProcessedEventHandler MessageProcessed;
        public event IACHooksEvents_AC3DRegionChangedEventHandler AC3DRegionChanged;
        public event IACHooksEvents_ContainerOpenedEventHandler ContainerOpened;
        public event IACHooksEvents_ChatClickInterceptEventHandler ChatClickIntercept;
        public event IACHooksEvents_RenderPreUIEventHandler RenderPreUI;

        private DecalCoreImpl _decal;
        private IIdentifyFilter _idFilter;

        // State
        private int _currentSelection;
        private int _previousSelection;
        private int _selectedStackCount;
        private int _maxSelectedStackCount;
        private int _combatMode;
        private int _vendorId;
        private int _busyState;
        private int _busyStateId;
        private int _pointerState;
        private int _commandInterpreter;
        private int _openedContainer;
        private bool _chatState;
        private double _headingDegrees;
        private double _headingRadians;
        private int _landcell;
        private double _locationX, _locationY, _locationZ;
        private tagRECT _ac3dRegionRect;
        private tagRECT _acWindowRect;

        public void SetIDFilter(IIdentifyFilter pIDFilter) => _idFilter = pIDFilter;

        public void SetDecal(object pDecal)
        {
            _decal = pDecal as DecalCoreImpl;
        }

        // Hook availability
        public int HooksAvail =>
            (int)(eAvailableHooks.eCurrentSelect | eAvailableHooks.ePrevSelect |
                  eAvailableHooks.eCastSpell | eAvailableHooks.eMoveItem |
                  eAvailableHooks.eSelectItem | eAvailableHooks.eUseItem |
                  eAvailableHooks.eCombatMode | eAvailableHooks.eChatState |
                  eAvailableHooks.eStackCount | eAvailableHooks.eMaxStackCount |
                  eAvailableHooks.eVendorID | eAvailableHooks.eBusyState |
                  eAvailableHooks.eBusyStateID | eAvailableHooks.ePointerState |
                  eAvailableHooks.eMoveItemEx | eAvailableHooks.ePosition |
                  eAvailableHooks.eFaceHeading | eAvailableHooks.eAC3DRegion |
                  eAvailableHooks.eObjectDestroyed | eAvailableHooks.eSendTell |
                  eAvailableHooks.eSetAutorun | eAvailableHooks.eSetCombatMode |
                  eAvailableHooks.eGetMiscInt | eAvailableHooks.eGetAttribute |
                  eAvailableHooks.eGetSkill | eAvailableHooks.eGetVital |
                  eAvailableHooks.eHooksAvailEx);

        public bool HooksAvailEx => true;

        // Chat methods
        public void AddChatText(string szText, int lColor, int lTarget)
        {
            // In the open-source version, we fire this through the chat event system
            bool eat = false;
            ChatTextIntercept?.Invoke(szText, lColor, lTarget, ref eat);
        }

        public void AddChatTextRaw(string szText, int lColor, int lTarget)
        {
            AddChatText(szText, lColor, lTarget);
        }

        public void AddStatusText(string Text)
        {
            bool eat = false;
            StatusTextIntercept?.Invoke(Text, ref eat);
        }

        public void InvokeChatParser(string Text)
        {
            bool eat = false;
            ChatParserIntercept?.Invoke(Text, ref eat);
        }

        public void SetIdleTime(double dIdleTimeout) { }

        public void Logout() { }

        // Selection
        public int CurrentSelection { get => _currentSelection; set => _currentSelection = value; }
        public int PreviousSelection { get => _previousSelection; set => _previousSelection = value; }
        public int SelectedStackCount { get => _selectedStackCount; set => _selectedStackCount = value; }
        public int MaxSelectedStackCount => _maxSelectedStackCount;

        public void SetCursorPosition(int lX, int lY) { }

        // Window/region info
        public tagRECT AC3DRegionRect => _ac3dRegionRect;
        public IntPtr AC3DRegionRectPtr => IntPtr.Zero;
        public tagRECT ACWindowRect => _acWindowRect;

        // State properties
        public bool ChatState => _chatState;
        public int BusyState => _busyState;
        public int BusyStateID => _busyStateId;
        public int PointerState => _pointerState;
        public int VendorID => _vendorId;

        // Vendor operations
        public void VendorBuyListAdd(int lID, int lAmount) { }
        public void VendorBuyListClear() { }
        public void VendorBuyAll() { }
        public void VendorSellListAdd(int lID) { }
        public void VendorSellListClear() { }
        public void VendorSellAll() { }

        // Combat
        public int CombatMode => _combatMode;
        public void SetCombatMode(int pVal) { _combatMode = pVal; }
        public void SetAutorun(bool bOnOff) { }
        public bool FaceHeading(float fHeading, bool bUnknown) { return true; }

        public int CommandInterpreter => _commandInterpreter;

        // Item operations
        public void SelectItem(int lObjectID)
        {
            _previousSelection = _currentSelection;
            _currentSelection = lObjectID;
            ObjectSelected?.Invoke(lObjectID);
        }

        public void GiveItem(int lObject, int lDestination) { }
        public void ApplyItem(int UseThis, int OnThis) { }
        public void UseItem(int lObjectID, int lUseState) { }
        public void UseItemRaw(int lObjectID, int lUseState, int lUseMethod) { }
        public void MoveItem(int lObjectID, int lPackID, int lSlot, bool bStack) { }
        public void MoveItemEx(int lObjectID, int lDestinationID) { }
        public void MoveItemExRaw(int lObject, int lDestination, int lMoveFlags) { }
        public void DropItem(int lObjectID) { }

        // Spell casting
        public void CastSpell(int lSpellID, int lObjectID) { }

        // Object queries
        public bool IsValidObject(int lGUID) => false;
        public int GetWeenieObjectPtr(int lObjectID) => 0;
        public int GetPhysicsObjectPtr(int lObjectID) => 0;

        // Position
        public double HeadingDegrees => _headingDegrees;
        public double HeadingRadians => _headingRadians;
        public int Landcell => _landcell;
        public double LocationX => _locationX;
        public double LocationY => _locationY;
        public double LocationZ => _locationZ;

        // Character stats (parameterized properties — index-based access)
        public eTrainLevel SkillTrainLevel => eTrainLevel.eUntrained;
        public int SkillTotalXP => 0;
        public int SkillFreePoints => 0;
        public int SkillClicks => 0;
        public int AttributeTotalXP => 0;
        public int AttributeClicks => 0;
        public int AttributeStart => 0;
        public int VitalTotalXP => 0;
        public int VitalClicks => 0;
        public int Vital => 0;
        public int Attribute => 0;
        public int Skill => 0;
        public int Misc => 0;

        // ID/object operations
        public void RequestID(int lObjectID) { _idFilter?.AddToQueue(lObjectID); }
        public void IDQueueAdd(int lObjectID) { _idFilter?.AddToQueue(lObjectID); }

        // Spell bar
        public void SpellTabAdd(int lTab, int lIndex, int lSpellID) { }
        public void SpellTabDelete(int lTab, int lSpellID) { }

        // Trade
        public void TradeAdd(int ItemID) { }
        public void TradeAccept() { }
        public void TradeDecline() { }
        public void TradeReset() { }
        public void TradeEnd() { }

        // Salvage
        public void SalvagePanelAdd(int lObjectID) { }
        public void SalvagePanelSalvage() { }

        public int OpenedContainer => _openedContainer;

        // Experience
        public void AddSkillExp(eSkill SkillID, int lExperience) { }
        public void AddAttributeExp(eAttribute AttribID, int lExperience) { }
        public void AddVitalExp(eVital VitalID, int lExperience) { }

        public int SmartboxPtr() => 0;
        public float ObjectHeight(int lObjectID) => 0f;

        public int CallerRefInstanceInternal { set { } }

        // Equipment
        public void AutoWieldRaw(int lObjectID, int SlotID, int Explicit, int NotExplicit, int zeroVal1, int zeroVal2) { }
        public void AutoWield(int lObjectID) { }
        public void AutoWieldEx(int lObjectID, int SlotID, int Explicit, int NotExplicit) { }

        // Fellowship
        public void FellowshipRecruit(int lObjectID) { }
        public void FellowshipGrantLeader(int lObjectID) { }
        public void FellowshipSetOpen(bool IsOpen) { }
        public void FellowshipQuit() { }
        public void FellowshipDisband() { }
        public void FellowshipDismiss(int lObjectID) { }

        // UI
        public void UIElementMove(int lUIElementType, int X, int Y) { }
        public void UIElementResize(int lUIElementType, int Width, int Height) { }
        public int UIElementLookup(int lUIElementType) => 0;
        public tagRECT UIElementRegionRect(int lUIElementType) => default;

        // Internal event firing methods
        internal void FireObjectDestroyed(int guid) => ObjectDestroyed?.Invoke(guid);
        internal void FireContainerOpened(int guid) => ContainerOpened?.Invoke(guid);
        internal void FireRenderPreUI() => RenderPreUI?.Invoke();

        internal void FireChatText(string text, int color, int target, ref bool eat)
        {
            ChatTextIntercept?.Invoke(text, color, target, ref eat);
        }

        internal void FireChatParser(string text, ref bool eat)
        {
            ChatParserIntercept?.Invoke(text, ref eat);
        }

        internal void FireStatusText(string text, ref bool eat)
        {
            StatusTextIntercept?.Invoke(text, ref eat);
        }

        internal void FireObjectSelected(int guid) => ObjectSelected?.Invoke(guid);

        internal void FireAC3DRegionChanged(int left, int top, int right, int bottom)
        {
            _ac3dRegionRect = new tagRECT { left = left, top = top, right = right, bottom = bottom };
            AC3DRegionChanged?.Invoke(left, top, right, bottom);
        }

        internal void FireChatClick(string text, int id, ref bool eat)
        {
            ChatClickIntercept?.Invoke(text, id, ref eat);
        }

        internal void UpdatePosition(double x, double y, double z, int landcell, double headDeg, double headRad)
        {
            _locationX = x;
            _locationY = y;
            _locationZ = z;
            _landcell = landcell;
            _headingDegrees = headDeg;
            _headingRadians = headRad;
        }
    }
}
