using System.Collections.Concurrent;
using System.IO;
using NexusShell.Models;

namespace NexusShell.Services.Deployment;

/// <summary>
/// Tracks installed package metadata and in-progress deployment phases.
/// </summary>
public sealed class NexusPackageRegistry
{
    private readonly NexusPackageRepository _repository;
    private readonly ConcurrentDictionary<string, NexusDeploymentPhase> _activePhases = new(StringComparer.OrdinalIgnoreCase);
    private readonly ConcurrentDictionary<string, string?> _failureReasons = new(StringComparer.OrdinalIgnoreCase);

    public NexusPackageRegistry(NexusPackageRepository repository)
    {
        _repository = repository;
    }

    public NexusInstalledPackageRecord? GetRecord(string packageId) =>
        _repository.GetInstalledRecord(packageId);

    public IReadOnlyList<NexusInstalledPackageRecord> GetAllRecords() =>
        _repository.GetInstalledRecords();

    public bool IsInstalled(string packageId)
    {
        var record = GetRecord(packageId);
        return record is not null &&
               record.State is NexusPackageState.Installed or NexusPackageState.UpdateAvailable &&
               !string.IsNullOrWhiteSpace(record.InstalledVersion);
    }

    public string? GetInstalledVersion(string packageId) => GetRecord(packageId)?.InstalledVersion;

    public NexusDeploymentPhase GetActivePhase(string packageId) =>
        _activePhases.TryGetValue(packageId, out var phase) ? phase : NexusDeploymentPhase.None;

    public string? GetFailureReason(string packageId) =>
        _failureReasons.TryGetValue(packageId, out var reason) ? reason : null;

    public void SetActivePhase(string packageId, NexusDeploymentPhase phase)
    {
        if (phase is NexusDeploymentPhase.None)
        {
            _activePhases.TryRemove(packageId, out _);
            return;
        }

        _activePhases[packageId] = phase;
        _failureReasons.TryRemove(packageId, out _);
    }

    public void SetFailed(string packageId, string reason)
    {
        _activePhases[packageId] = NexusDeploymentPhase.Failed;
        _failureReasons[packageId] = reason;
    }

    public void ClearActive(string packageId)
    {
        _activePhases.TryRemove(packageId, out _);
        _failureReasons.TryRemove(packageId, out _);
    }

    public void SaveInstalled(
        string packageId,
        string version,
        NexusPackageState state = NexusPackageState.Installed,
        string? stateReason = null)
    {
        var record = new NexusInstalledPackageRecord
        {
            Id = packageId,
            InstalledVersion = version,
            InstalledAt = DateTimeOffset.UtcNow,
            State = state,
            StateReason = stateReason,
        };

        _repository.SaveInstalledRecord(record);
        ClearActive(packageId);
    }

    public void MarkBroken(string packageId, string reason)
    {
        var existing = GetRecord(packageId);
        _repository.SaveInstalledRecord(new NexusInstalledPackageRecord
        {
            Id = packageId,
            InstalledVersion = existing?.InstalledVersion ?? string.Empty,
            InstalledAt = existing?.InstalledAt ?? DateTimeOffset.UtcNow,
            State = NexusPackageState.Broken,
            StateReason = reason,
        });
        SetFailed(packageId, reason);
    }

    public void Remove(string packageId)
    {
        _repository.RemoveInstalledRecord(packageId);
        ClearActive(packageId);
    }

    public string GetInstalledDirectory(string packageId) =>
        Path.Combine(_repository.InstalledDirectory, packageId);
}
