using System;
using System.Diagnostics;

namespace AutoIngest.Engine
{
    /// <summary>
    /// Deals with the awkward reality that Windows disables <c>LastAccessTime</c> updates by
    /// default (since Vista, for performance). Retention can still work using
    /// <c>LastWriteTime</c> (import date), but true "was this folder opened recently?" tracking
    /// needs access times to be on. This class detects the current state and offers to enable
    /// it (which requires admin + a restart to fully take effect).
    ///
    /// We never silently change system settings. The UI shows the status and, if the user opts
    /// in, launches an elevated <c>fsutil</c> that Windows will prompt UAC for.
    /// </summary>
    public static class AccessTimeTracker
    {
        /// <summary>
        /// Whether NTFS is currently updating LastAccessTime on file reads. Conservative: only
        /// returns true when we get a clear "enabled" signal from fsutil. Unknown / system-managed
        /// modes return false so the UI degrades to the LastWriteTime fallback.
        /// </summary>
        public static bool IsEnabled()
        {
            try
            {
                var (output, exitCode) = RunFsutil("behavior query DisableLastAccess");
                if (exitCode != 0 || string.IsNullOrWhiteSpace(output)) return false;
                return ParseDisableLastAccess(output);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Attempts to enable access-time updates by launching an elevated fsutil. Returns true
        /// if the elevated process was launched (the UAC prompt was accepted); false if the user
        /// declined elevation or launch failed. The actual effect requires a reboot, which the
        /// caller is responsible for communicating.
        /// </summary>
        public static bool TryEnable()
        {
            try
            {
                var psi = new ProcessStartInfo
                {
                    FileName = "fsutil.exe",
                    Arguments = "behavior set DisableLastAccess 0",
                    Verb = "runas",                // triggers UAC
                    UseShellExecute = true,        // required for Verb = runas
                    WindowStyle = ProcessWindowStyle.Hidden,
                    CreateNoWindow = true
                };
                using var p = Process.Start(psi);
                if (p == null) return false;
                // Don't block forever — fsutil is fast, but UAC might be pending. 30s is plenty
                // for the user to respond to the prompt.
                return p.WaitForExit(30000) && p.ExitCode == 0;
            }
            catch (System.ComponentModel.Win32Exception)
            {
                // User cancelled the UAC prompt (ERROR_CANCELLED).
                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Parses <c>fsutil behavior query DisableLastAccess</c> output.
        /// Historical values:
        ///   0            = enabled (updating access times)
        ///   1            = disabled (the Vista+ default)
        ///   80000003     = system-managed (Win10 1803+); may or may not update — treat as off
        /// The output line looks like "DisableLastAccess = 1" or includes a note line.
        /// </summary>
        static bool ParseDisableLastAccess(string output)
        {
            foreach (var raw in output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var line = raw.Trim();
                int eq = line.IndexOf('=');
                if (eq < 0) continue;
                var value = line.Substring(eq + 1).Trim();
                // Take the leading integer token (ignore trailing notes).
                var digits = new System.Text.StringBuilder();
                foreach (var ch in value)
                {
                    if (char.IsDigit(ch)) digits.Append(ch);
                    else if (digits.Length > 0) break;
                }
                if (digits.Length == 0) continue;
                if (!int.TryParse(digits.ToString(), out var n)) continue;
                // 0 = enabled. Anything else (1, system-managed codes) = treat as disabled.
                return n == 0;
            }
            return false;
        }

        static (string output, int exitCode) RunFsutil(string args)
        {
            var psi = new ProcessStartInfo
            {
                FileName = "fsutil.exe",
                Arguments = args,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true
            };
            using var p = Process.Start(psi);
            if (p == null) return ("", -1);
            var stdout = p.StandardOutput.ReadToEnd();
            p.WaitForExit(5000);
            return (stdout, p.ExitCode);
        }
    }
}
