using Microsoft.Win32;
using System.Management;
using System.Runtime.Versioning;
using System.Security.Principal;

namespace OnAir
{
    [SupportedOSPlatform("Windows")]
    internal class WebCamWatcher
    {
        public delegate void WebCamEventHandler();

        const string mgmtRoot = @"\\.\root\default";
        const string baseKeyName = @"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam";
        const string timeStampName = "LastUsedTimeStop";

        private ManagementScope _scope;
        private EventQuery _query;
        private ManagementEventWatcher _watcher;
        private EventArrivedEventHandler? _handler;

        public WebCamWatcher()
        {
            string keyPath;
            var myIdentity = WindowsIdentity.GetCurrent().User;
            if (myIdentity != null) { 
                keyPath = myIdentity.ToString();
            }
            else
            {
                keyPath = "S-1-0-0";
            }
            keyPath += @"\" + baseKeyName;
            keyPath = keyPath.Replace(@"\", @"\\");
            _scope = new ManagementScope(mgmtRoot);
            _query = new EventQuery(@"SELECT * FROM RegistryTreeChangeEvent WHERE Hive='HKEY_USERS' AND RootPath='" + keyPath + "'");
            _watcher = new ManagementEventWatcher(_scope, _query);
        }

        public void Watch(WebCamEventHandler handler)
        {
            if (_handler != null) {
                throw new InvalidOperationException("Already watching.");
            }
            _handler = new EventArrivedEventHandler((s, e) => handler());
            _watcher.EventArrived += _handler;
            _watcher.Start();
        }

        public void EndWatch()
        {
            if (_handler == null) {
                throw new InvalidOperationException("Not watching.");
            }
            _watcher.Stop();
            _watcher.EventArrived -= _handler;
            _handler = null;
        }

        public static IEnumerable<string> GetAppsUsingCam()
        {
            var answer = new List<string>();
            using (var baseKey = Registry.CurrentUser.OpenSubKey(baseKeyName)) {
                if (baseKey != null) {
                    foreach (var subKeyName in baseKey.GetSubKeyNames()) {
                        using (var subKey = baseKey.OpenSubKey(subKeyName)) {
                            if (subKey != null) {
                                if (subKeyName == "NonPackaged") {
                                    foreach (var npSubKeyName in subKey.GetSubKeyNames()) {
                                        using (var npSubKey = subKey.OpenSubKey(npSubKeyName)) {
                                            if (npSubKey != null) {
                                                var npTimeStamp = npSubKey.GetValue(timeStampName, -1L);
                                                if (npTimeStamp != null && (long)npTimeStamp == 0) {
                                                    answer.Add(npSubKeyName);
                                                }
                                            }
                                        }
                                    }
                                }
                                else {
                                    var timeStamp = subKey.GetValue(timeStampName, -1L);
                                    if (timeStamp != null && (long)timeStamp == 0) {
                                        answer.Add(subKeyName);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return answer;
        }
    }
}
