using System;
using ArchestrA.MxAccess;

namespace MxAccess.Cli.Mx
{
    /// One AddItem-handle. Owns Advise/UnAdvise pairing so a Dispose tears
    /// down the subscription cleanly even if the caller forgets.
    public sealed class MxItem : IDisposable
    {
        private readonly MxSession _session;
        private readonly LMXProxyServerClass _proxy;
        private readonly int _hServer;
        private bool _advised;
        private bool _disposed;

        public int Handle { get; }
        public string Reference { get; }

        internal MxItem(MxSession session, LMXProxyServerClass proxy, int hServer, int hItem, string reference)
        {
            _session  = session;
            _proxy    = proxy;
            _hServer  = hServer;
            Handle    = hItem;
            Reference = reference;
        }

        public void Advise()
        {
            if (_advised) return;
            _proxy.Advise(_hServer, Handle);
            _advised = true;
        }

        /// Subscribe in supervisory mode. Use this for actions that should
        /// be attributed to the hosting client (rather than to a Galaxy user)
        /// in the alarm/event audit trail — e.g. anonymous bulk operators,
        /// integration scripts, or automation acting on its own authority.
        /// Pairs with the same UnAdvise / RemoveItem teardown as Advise().
        public void AdviseSupervisory()
        {
            if (_advised) return;
            _proxy.AdviseSupervisory(_hServer, Handle);
            _advised = true;
        }

        public void UnAdvise()
        {
            if (!_advised) return;
            try { _proxy.UnAdvise(_hServer, Handle); } catch { /* best effort */ }
            _advised = false;
        }

        /// `Write` blocks neither the caller nor the proxy — it queues a write and
        /// returns. Use MxSession.WaitForUpdate() to await OnWriteComplete.
        /// `userId = 0` means "unauthenticated"; OK for simple writes when galaxy
        /// security allows it.
        public void Write(object value, int userId = 0) =>
            _proxy.Write(_hServer, Handle, value, userId);

        /// Two-user Secured/Verified write. Propagates the user identity into
        /// the alarm/event audit trail in a way that the engine's audit
        /// subsystem honors for Secured Write / Verified Write attribute
        /// security classifications.
        ///
        /// For single-user Secured Write, pass the same id for both
        /// `currentUserId` and `verifierUserId`. For two-person Verified Write,
        /// pass two distinct authenticated user ids (operator + verifier).
        public void WriteSecured(object value, int currentUserId, int verifierUserId) =>
            _proxy.WriteSecured(_hServer, Handle, currentUserId, verifierUserId, value);

        public void Dispose()
        {
            if (_disposed) return;
            _disposed = true;
            try { UnAdvise(); } catch { }
            try { _proxy.RemoveItem(_hServer, Handle); } catch { }
            _session.RemoveItem(Handle);
        }
    }
}
