using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Options;

public class PhiAccessLogService : IPhiAccessLogService
{
    private readonly AppDbContext _db;
    private readonly ICurrentUserService _currentUser;
    private readonly IHttpContextAccessor _http;
    private readonly PhiEncryptionOptions _options;
    private readonly ClinicalMetrics _metrics;

    public PhiAccessLogService(
        AppDbContext db,
        ICurrentUserService currentUser,
        IHttpContextAccessor http,
        IOptions<PhiEncryptionOptions> options,
        ClinicalMetrics metrics)
    {
        _db = db;
        _currentUser = currentUser;
        _http = http;
        _options = options.Value;
        _metrics = metrics;
    }

    public async Task LogViewAsync(Guid patientId, string resourcePath) =>
        await WriteAsync(PhiAccessType.View, patientId, resourcePath);

    public async Task LogCreateAsync(Guid patientId, string resourcePath) =>
        await WriteAsync(PhiAccessType.Create, patientId, resourcePath);

    public async Task LogUpdateAsync(Guid patientId, string resourcePath) =>
        await WriteAsync(PhiAccessType.Update, patientId, resourcePath);

    public async Task LogListAsync(string resourcePath, int resultCount, string? searchQuery = null)
    {
        if (!_options.LogListAccess)
            return;

        var accessType = string.IsNullOrWhiteSpace(searchQuery)
            ? PhiAccessType.List
            : PhiAccessType.Search;

        await WriteAsync(accessType, null, resourcePath, resultCount, searchQuery);
    }

    private async Task WriteAsync(
        PhiAccessType accessType,
        Guid? patientId,
        string resourcePath,
        int? resultCount = null,
        string? searchQuery = null)
    {
        if (!_currentUser.IsAuthenticated || _currentUser.UserId is null)
            return; // machine/integration paths may skip — Phase 31 Integration role should still auth

        _db.PhiAccessLogs.Add(new PhiAccessLog
        {
            Id = Guid.NewGuid(),
            AccessType = accessType,
            PatientId = patientId,
            UserId = _currentUser.UserId.Value,
            UserDisplayName = _currentUser.DisplayName ?? _currentUser.Username ?? "Unknown",
            ResourcePath = resourcePath,
            SearchQueryHash = searchQuery is null ? null : HashQuery(searchQuery),
            ResultCount = resultCount,
            IpAddress = _currentUser.IpAddress,
            CorrelationId = _http.HttpContext?.Items["CorrelationId"]?.ToString(),
            AccessedAt = DateTimeOffset.UtcNow
        });

        await _db.SaveChangesAsync();

        _metrics.PhiAccessLogsTotal.WithLabels(accessType.ToDbString()).Inc();
    }

    private static string HashQuery(string query)
    {
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(query.Trim().ToLowerInvariant()));
        return Convert.ToHexString(hash).ToLowerInvariant();
    }
}