using Nexus.Contracts.Apps;
using NexusShell.Models;
using NexusShell.Services;
using NexusShell.Services.Identity;

namespace NexusShell.Services.Policy;

public sealed class NexusPolicyService
{
    private readonly NexusPolicyStore _store;
    private readonly NexusPolicyEvaluator _evaluator;
    private readonly ProfileService _profile;
    private readonly NexusIdentityService? _identity;
    private NexusRolePolicy _active;

    public NexusPolicyService(
        NexusPolicyStore store,
        NexusPolicyEvaluator evaluator,
        ProfileService profile,
        NexusIdentityService? identity = null)
    {
        _store = store;
        _evaluator = evaluator;
        _profile = profile;
        _identity = identity;
        _active = ResolveActivePolicy();
    }

    public NexusPolicy ActivePolicy => _active.Policy;

    public NexusRole ActiveRole => _active.Role;

    public string PoliciesDirectory => _store.PoliciesDirectory;

    public void Refresh()
    {
        _store.Reload();
        _active = ResolveActivePolicy();
        PolicyChanged?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler? PolicyChanged;

    public bool CanLaunchApp(AppEntry app) =>
        CanLaunchApp(NexusPolicyAppKeys.FromAppEntry(app));

    public bool CanLaunchApp(string appKey)
    {
        var trust = CurrentTrust;
        return _evaluator.IsAppAllowed(_active.Policy, appKey, _active.Role, trust);
    }

    public bool IsAppAllowed(AppEntry app) => CanLaunchApp(app);

    public bool IsAppAllowed(string appKey) => CanLaunchApp(appKey);

    public bool IsPackageAllowed(string packageId) =>
        CanLaunchApp(NexusPolicyAppKeys.FromPackageId(packageId));

    public bool IsDockItemAllowed(string dockLabel) =>
        CanLaunchApp(NexusPolicyAppKeys.FromDockLabel(dockLabel));

    public bool IsFeatureAllowed(string featureKey)
    {
        var trust = CurrentTrust;
        return _evaluator.IsFeatureAllowed(_active.Policy, featureKey, _active.Role, trust);
    }

    public bool IsCommandAllowed(string command)
    {
        var trust = CurrentTrust;
        return _evaluator.IsCommandAllowed(_active.Policy, command, _active.Role, trust);
    }

    public bool IsSettingsSectionAllowed(string sectionName) =>
        _evaluator.IsSettingsSectionAllowed(_active.Policy, sectionName);

    public bool CanAccessConsole() =>
        _evaluator.CanAccessConsole(_active.Policy, _active.Role, CurrentTrust);

    public bool CanAccessStore() =>
        _evaluator.CanAccessStore(_active.Policy, _active.Role, CurrentTrust);

    public bool CanOpenBrowser() =>
        CanLaunchApp("browser") && IsFeatureAllowed("browser");

    public bool CanOpenFiles() =>
        CanLaunchApp("files") && IsFeatureAllowed("files");

    public bool CanOpenDeviceManager() =>
        CanLaunchApp("device-manager") && IsFeatureAllowed("device-manager");

    public bool CanOpenPhotos() =>
        CanLaunchApp("photos") && IsFeatureAllowed("photos");

    public bool CanOpenMedia() =>
        CanLaunchApp("media") && IsFeatureAllowed("media");

    public bool CanOpenCalculator() =>
        CanLaunchApp("calculator") && IsFeatureAllowed("calculator");

    public bool CanOpenSettings() =>
        CanLaunchApp("settings") && IsFeatureAllowed("settings");

    public IEnumerable<AppEntry> FilterVisibleApps(IEnumerable<AppEntry> apps) => FilterApps(apps);

    public IEnumerable<AppEntry> FilterApps(IEnumerable<AppEntry> apps) =>
        apps.Where(CanLaunchApp);

    public NexusPolicySnapshot GetSnapshot()
    {
        var policy = _active.Policy;
        return new NexusPolicySnapshot
        {
            Role = _active.Role.ToString(),
            PolicyId = policy.Id,
            PolicyName = policy.Name,
            PolicyVersion = policy.Version,
            SourcePath = _active.SourcePath,
            EvaluatedAtUtc = DateTimeOffset.UtcNow,
            AllowApps = policy.AllowApps.ToList(),
            DenyApps = policy.DenyApps.ToList(),
            AllowFeatures = policy.AllowFeatures.ToList(),
            DenyFeatures = policy.DenyFeatures.ToList(),
            AllowCommands = policy.AllowCommands.ToList(),
            DenyCommands = policy.DenyCommands.ToList(),
            DenySettingsSections = policy.DenySettingsSections.ToList(),
            ConsoleAccess = CanAccessConsole(),
            StoreAccess = CanAccessStore(),
        };
    }

    private NexusTrustStatus CurrentTrust =>
        _identity?.GetSnapshot().Trust?.Status ?? NexusTrustStatus.Unknown;

    private NexusRolePolicy ResolveActivePolicy()
    {
        var roleName = _profile.CurrentProfile?.Role ?? _profile.LoadProfile()?.Role;
        var role = NexusPolicyEvaluator.ParseRole(roleName);
        return _store.GetForRoleOrDefault(role);
    }
}
