using NexusShell.Models;
using NexusShell.Services.Policy;

namespace NexusShell.Services;

public sealed class NexusConsoleService
{
    private readonly NexusCommandRegistry _registry;
    private readonly NexusConsoleAuditService _audit;
    private readonly ProfileService _profile;
    private readonly LockdownService _lockdown;
    private readonly NexusPlatformLockService _platformLock;
    private readonly UpdateService _updateService;
    private readonly AppCatalogService _catalog;
    private readonly SystemStatusService _systemStatus;
    private readonly NexusPolicyService _policy;

    public NexusConsoleService(
        NexusCommandRegistry registry,
        NexusConsoleAuditService audit,
        ProfileService profile,
        LockdownService lockdown,
        NexusPlatformLockService platformLock,
        UpdateService updateService,
        AppCatalogService catalog,
        SystemStatusService systemStatus,
        NexusPolicyService policy)
    {
        _registry = registry;
        _audit = audit;
        _profile = profile;
        _lockdown = lockdown;
        _platformLock = platformLock;
        _updateService = updateService;
        _catalog = catalog;
        _systemStatus = systemStatus;
        _policy = policy;
    }

    public bool CanAccessRole(string? role) =>
        _policy.CanAccessConsole() ||
        NexusCommandRegistry.CanAccessRole(role);

    public string AuditFilePath => _audit.AuditFilePath;

    public NexusCommandResult Execute(string input)
    {
        var profile = _profile.CurrentProfile;
        var user = profile?.Email ?? "unknown";
        var role = profile?.Role ?? "User";
        var trimmed = input.Trim();

        if (trimmed.Length == 0)
        {
            return NexusCommandResult.Output();
        }

        var blockedToken = _registry.GetBlockedToken(trimmed);
        if (blockedToken is not null)
        {
            var blockedResult = NexusCommandResult.Blocked(
                $"Blocked: '{blockedToken}' is not permitted in Nexus Console.");
            LogAudit(user, role, trimmed, blockedResult);
            return blockedResult;
        }

        var parts = trimmed.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
        var command = parts[0].ToLowerInvariant();
        var args = parts.Length > 1 ? parts[1] : string.Empty;

        if (!_policy.IsCommandAllowed(command))
        {
            var policyBlocked = NexusCommandResult.Blocked(
                $"Blocked by policy: '{command}' is not permitted for role {_policy.ActiveRole}.");
            LogAudit(user, role, trimmed, policyBlocked);
            return policyBlocked;
        }

        NexusCommandResult result;
        if (!_registry.IsWhitelisted(command))
        {
            result = NexusCommandResult.Unknown();
        }
        else
        {
            result = command switch
            {
                "help" => ExecuteHelp(),
                "version" => ExecuteVersion(),
                "status" => ExecuteStatus(),
                "whoami" => ExecuteWhoAmI(profile),
                "clear" => NexusCommandResult.WithAction(NexusConsoleAction.ClearOutput),
                "restart-shell" => NexusCommandResult.WithAction(
                    NexusConsoleAction.RestartShell,
                    "Restarting Nexus Shell…"),
                "open-logs" => ExecuteOpenLogs(),
                "show-config" => ExecuteShowConfig(),
                "lockdown-status" => ExecuteLockdownStatus(),
                "platform-lock-status" => ExecutePlatformLockStatus(),
                "windows-lock" => ExecuteWindowsLock(),
                "windows-unlock" => ExecuteWindowsUnlock(args),
                "update-check" => ExecuteUpdateCheck(),
                "apps-list" => ExecuteAppsList(),
                "browser-test" => NexusCommandResult.WithAction(
                    NexusConsoleAction.OpenBrowser,
                    string.IsNullOrWhiteSpace(args) ? "https://nexus.ninjakernen.info" : args,
                    "Opening Nexus Browser (POC test)…"),
                "files-test" => NexusCommandResult.WithAction(
                    NexusConsoleAction.OpenFiles,
                    string.IsNullOrWhiteSpace(args) ? "documents" : args,
                    "Opening Nexus Files (POC test)…"),
                "exit" => NexusCommandResult.WithAction(NexusConsoleAction.ExitConsole, "Closing Nexus Console."),
                _ => NexusCommandResult.Unknown(),
            };
        }

        LogAudit(user, role, trimmed, result);
        return result;
    }

    public void LogAccessDenied(string? role)
    {
        var profile = _profile.CurrentProfile;
        _audit.Log(
            profile?.Email ?? "unknown",
            role ?? profile?.Role ?? "User",
            "(access-denied)",
            "Adgang nægtet. Nexus Console kræver Developer-adgang.",
            false);
    }

    public void LogConsoleOpened()
    {
        var profile = _profile.CurrentProfile;
        _audit.Log(
            profile?.Email ?? "unknown",
            profile?.Role ?? "User",
            "(console-open)",
            "Nexus Console session opened",
            true);
    }

    private void LogAudit(string user, string role, string command, NexusCommandResult result)
    {
        var summary = result.Lines.Count > 0
            ? string.Join("; ", result.Lines.Take(3))
            : result.Action.ToString();
        _audit.Log(user, role, command, summary, result.Allowed);
    }

    private NexusCommandResult ExecuteHelp()
    {
        var lines = new List<string>
        {
            "Nexus Console 1.0 POC — whitelisted commands:",
        };
        lines.AddRange(_registry.Commands.OrderBy(c => c).Select(c => $"  {c}"));
        lines.Add("");
        lines.Add("Type a command after the nexus> prompt. No Windows passthrough.");
        return NexusCommandResult.Output(lines.ToArray());
    }

    private NexusCommandResult ExecuteVersion() =>
        NexusCommandResult.Output(
            $"Nexus Shell {_updateService.CurrentVersion} (build {_updateService.CurrentBuild})",
            "Channel: POC local build");

    private NexusCommandResult ExecuteStatus()
    {
        var snap = _systemStatus.Capture();
        return NexusCommandResult.Output(
            $"System: {snap.SystemStatus}",
            $"Network: {snap.NetworkLabel} ({(snap.IsOnline ? "online" : "offline")})",
            $"CPU: {snap.CpuPercent}%  Memory: {snap.MemoryLabel} ({snap.MemoryLoadPercent}%)",
            $"Storage: {snap.StorageLabel}",
            $"Health: {snap.HealthPercent}%",
            $"Identity latency: {snap.IdentityLatencyLabel}");
    }

    private static NexusCommandResult ExecuteWhoAmI(LocalUserProfile? profile)
    {
        if (profile is null)
        {
            return NexusCommandResult.Output("Not signed in.");
        }

        return NexusCommandResult.Output(
            $"User: {profile.DisplayName} ({profile.Email})",
            $"Role: {profile.Role}",
            $"UserId: {profile.UserId}");
    }

    private NexusCommandResult ExecuteOpenLogs() =>
        NexusCommandResult.Output(
            "Audit log (Nexus Console):",
            $"  {_audit.AuditFilePath}",
            "Lockdown audit:",
            $"  {_lockdown.AuditFilePath}",
            "POC: logs are not opened externally for safety.");

    private NexusCommandResult ExecuteShowConfig() =>
        NexusCommandResult.Output(
            "Nexus Shell POC configuration:",
            $"  Safe POC: {_lockdown.IsSafePocEnabled}",
            $"  Lockdown mode: {_lockdown.IsLockdownActive}",
            $"  Developer console enabled: {_lockdown.DeveloperConsoleEnabled}",
            $"  Allowed apps: {_lockdown.AllowedAppsCount}",
            $"  Blocked apps: {_lockdown.BlockedAppsCount}",
            $"  Update manifest: {_updateService.ManifestUrl}");

    private NexusCommandResult ExecutePlatformLockStatus() =>
        NexusCommandResult.Output(
            _platformLock.StatusLabel,
            $"Lockdown bypass: {!_platformLock.IsWindowsLocked}",
            $"Unlock chord: {_platformLock.Config.KeyChord}");

    private NexusCommandResult ExecuteWindowsLock()
    {
        var profile = _profile.CurrentProfile;
        var actor = profile?.Email ?? "console";
        _platformLock.Lock(actor);
        return NexusCommandResult.Output("Windows locked — Nexus shell owns the desktop.");
    }

    private NexusCommandResult ExecuteWindowsUnlock(string args)
    {
        if (string.IsNullOrWhiteSpace(args))
        {
            return NexusCommandResult.Output("Usage: windows-unlock <pin>");
        }

        var profile = _profile.CurrentProfile;
        var actor = profile?.Email ?? "console";
        if (_platformLock.TryUnlock(args.Trim(), actor))
        {
            return NexusCommandResult.Output(
                "Windows unlocked (POC).",
                _platformLock.StatusLabel);
        }

        return NexusCommandResult.Output("Unlock failed — invalid PIN.");
    }

    private NexusCommandResult ExecuteLockdownStatus()
    {
        if (!_lockdown.IsSafePocEnabled)
        {
            return NexusCommandResult.Output("Lockdown: Disabled (not in safe POC mode)");
        }

        return NexusCommandResult.Output(
            _lockdown.IsLockdownActive
                ? "Lockdown: ACTIVE — app launches restricted to whitelist"
                : "Lockdown: INACTIVE — config loaded but not enforcing",
            $"Allowed apps: {_lockdown.AllowedAppsCount}",
            $"Blocked tokens: {_lockdown.BlockedAppsCount}",
            $"Windows escape: {_lockdown.Config.AllowWindowsEscape}");
    }

    private NexusCommandResult ExecuteUpdateCheck()
    {
        try
        {
            var check = _updateService.CheckForUpdatesAsync().GetAwaiter().GetResult();
            return check.Status switch
            {
                UpdateCheckStatus.UpToDate => NexusCommandResult.Output(
                    "Update check: Up to date",
                    $"Installed: {_updateService.CurrentVersion} (build {_updateService.CurrentBuild})"),
                UpdateCheckStatus.UpdateAvailable => NexusCommandResult.Output(
                    "Update check: Update available",
                    $"Remote: {check.RemoteManifest?.Version ?? "unknown"} (build {check.RemoteManifest?.Build ?? 0})",
                    string.Join(" ", check.RemoteManifest?.ReleaseNotes ?? [])),
                UpdateCheckStatus.ChannelUnavailable => NexusCommandResult.Output(
                    "Update check: Channel unavailable",
                    check.ErrorMessage ?? "Could not reach update manifest"),
                UpdateCheckStatus.Error => NexusCommandResult.Output(
                    "Update check: Error",
                    check.ErrorMessage ?? "Unknown error"),
                _ => NexusCommandResult.Output("Update check: Completed", _updateService.StatusSummary),
            };
        }
        catch (Exception ex)
        {
            return NexusCommandResult.Output("Update check failed", ex.Message);
        }
    }

    private NexusCommandResult ExecuteAppsList()
    {
        var apps = _policy.FilterVisibleApps(_catalog.Apps).ToList();
        if (apps.Count == 0)
        {
            return NexusCommandResult.Output("No apps in catalog.");
        }

        var lines = new List<string> { $"Apps ({apps.Count}):" };
        foreach (var app in apps.Take(30))
        {
            lines.Add($"  {app.Id,-20} {app.Name}");
        }

        if (apps.Count > 30)
        {
            lines.Add($"  … and {apps.Count - 30} more");
        }

        return NexusCommandResult.Output(lines.ToArray());
    }
}
