using Books.Api.Domain.UserAccess;

namespace Books.Api.Authorization;

/// <summary>
/// Context for the currently selected company in a request.
/// Extracted from X-Company-Id header and validated against user access.
/// </summary>
public class CompanyContext
{
    /// <summary>
    /// The currently selected company ID.
    /// </summary>
    public string? CompanyId { get; init; }

    /// <summary>
    /// The user's role for the selected company.
    /// </summary>
    public CompanyRole? Role { get; init; }

    /// <summary>
    /// Whether a valid company is selected and the user has access.
    /// </summary>
    public bool HasCompanySelected => CompanyId != null && Role != null;

    /// <summary>
    /// Check if the user has at least the required role for the selected company.
    /// </summary>
    public bool HasRole(CompanyRole minimumRole)
    {
        if (Role == null) return false;

        return minimumRole switch
        {
            CompanyRole.Viewer => true,
            CompanyRole.Accountant => Role is CompanyRole.Owner or CompanyRole.Accountant,
            CompanyRole.Owner => Role is CompanyRole.Owner,
            _ => false
        };
    }

    /// <summary>
    /// Require the user to have at least the specified role.
    /// Throws DomainException if not.
    /// </summary>
    public void RequireRole(CompanyRole minimumRole)
    {
        if (!HasCompanySelected)
        {
            throw new Domain.DomainException(
                "NO_COMPANY_SELECTED",
                "No company selected. Set X-Company-Id header.",
                "Ingen virksomhed valgt. Sæt X-Company-Id header.");
        }

        if (!HasRole(minimumRole))
        {
            var roleDescription = minimumRole switch
            {
                CompanyRole.Owner => "ejer",
                CompanyRole.Accountant => "bogholder",
                CompanyRole.Viewer => "læser",
                _ => "ukendt"
            };

            throw new Domain.DomainException(
                "INSUFFICIENT_PERMISSIONS",
                $"This operation requires {minimumRole} role",
                $"Denne handling kræver {roleDescription}-rolle");
        }
    }

    /// <summary>
    /// Require that the user can write (Owner or Accountant).
    /// </summary>
    public void RequireWrite() => RequireRole(CompanyRole.Accountant);

    /// <summary>
    /// Require that the user is Owner.
    /// </summary>
    public void RequireOwner() => RequireRole(CompanyRole.Owner);
}
