using MediatR;
using IamService.Domain.AggregatesModel.ComplianceAggregate;
using IamService.Domain.Exceptions;

namespace IamService.API.Application.Commands.Compliance;

public record GenerateComplianceReportCommand(string Name, int ReportTypeId, Guid GeneratedByUserId) : IRequest<Guid>;
public record CompleteComplianceReportCommand(Guid ReportId, int TotalChecks, int PassedChecks, string? Summary = null) : IRequest<Unit>;
public record AddViolationCommand(Guid ReportId, string Rule, int SeverityId, string Description, string? Remediation = null) : IRequest<Guid>;

public class GenerateComplianceReportCommandHandler : IRequestHandler<GenerateComplianceReportCommand, Guid>
{
    private readonly IComplianceReportRepository _repository;
    public GenerateComplianceReportCommandHandler(IComplianceReportRepository repository) => _repository = repository;

    public async Task<Guid> Handle(GenerateComplianceReportCommand request, CancellationToken cancellationToken)
    {
        var reportType = ComplianceReportType.FromId(request.ReportTypeId) ?? ComplianceReportType.GDPR;
        var report = ComplianceReport.Create(request.Name, reportType, request.GeneratedByUserId);
        report.StartGenerating();
        _repository.Add(report);
        await _repository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return report.Id;
    }
}

public class CompleteComplianceReportCommandHandler : IRequestHandler<CompleteComplianceReportCommand, Unit>
{
    private readonly IComplianceReportRepository _repository;
    public CompleteComplianceReportCommandHandler(IComplianceReportRepository repository) => _repository = repository;

    public async Task<Unit> Handle(CompleteComplianceReportCommand request, CancellationToken cancellationToken)
    {
        var report = await _repository.GetByIdWithViolationsAsync(request.ReportId, cancellationToken)
            ?? throw new DomainException($"Report {request.ReportId} not found.");
        report.SetResults(request.TotalChecks, request.PassedChecks, request.Summary);
        report.Complete();
        _repository.Update(report);
        await _repository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return Unit.Value;
    }
}

public class AddViolationCommandHandler : IRequestHandler<AddViolationCommand, Guid>
{
    private readonly IComplianceReportRepository _repository;
    public AddViolationCommandHandler(IComplianceReportRepository repository) => _repository = repository;

    public async Task<Guid> Handle(AddViolationCommand request, CancellationToken cancellationToken)
    {
        var report = await _repository.GetByIdWithViolationsAsync(request.ReportId, cancellationToken)
            ?? throw new DomainException($"Report {request.ReportId} not found.");
        var severity = ViolationSeverity.FromId(request.SeverityId) ?? ViolationSeverity.Medium;
        report.AddViolation(request.Rule, severity, request.Description, request.Remediation);
        _repository.Update(report);
        await _repository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return report.Violations.Last().Id;
    }
}
