using ColaFlow.Modules.Mcp.Infrastructure.Auditing;
using ColaFlow.Modules.Mcp.Infrastructure.Reporting;
using ColaFlow.Modules.Mcp.Infrastructure.Validation;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;

namespace ColaFlow.IntegrationTests.Mcp;

/// <summary>
/// Tests for multi-tenant security report generation
/// </summary>
public class MultiTenantSecurityReportTests
{
    [Fact]
    public void SecurityReport_IsGenerated_Successfully()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<McpSecurityAuditLogger>>();
        var auditLogger = new McpSecurityAuditLogger(mockLogger.Object);

        var mockValidatorLogger = new Mock<ILogger<TenantContextValidator>>();
        var tenantValidator = new TenantContextValidator(mockValidatorLogger.Object);

        var reportGenerator = new MultiTenantSecurityReportGenerator(auditLogger, tenantValidator);

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert
        report.Should().NotBeNull();
        report.GeneratedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
        report.SecurityChecks.Should().NotBeNull();
        report.AuditStatistics.Should().NotBeNull();
        report.ValidationStatistics.Should().NotBeNull();
        report.OverallScore.Should().NotBeNull();
    }

    [Fact]
    public void SecurityReport_TextFormat_ContainsRequiredSections()
    {
        // Arrange
        var reportGenerator = new MultiTenantSecurityReportGenerator();

        // Act
        var textReport = reportGenerator.GenerateTextReport();

        // Assert
        textReport.Should().Contain("MULTI-TENANT SECURITY VERIFICATION REPORT");
        textReport.Should().Contain("OVERALL SECURITY SCORE");
        textReport.Should().Contain("SECURITY CHECKS");
        textReport.Should().Contain("AUDIT STATISTICS");
        textReport.Should().Contain("QUERY VALIDATION STATISTICS");
    }

    [Fact]
    public void SecurityReport_MarkdownFormat_ContainsRequiredSections()
    {
        // Arrange
        var reportGenerator = new MultiTenantSecurityReportGenerator();

        // Act
        var markdownReport = reportGenerator.GenerateMarkdownReport();

        // Assert
        markdownReport.Should().Contain("# Multi-Tenant Security Verification Report");
        markdownReport.Should().Contain("## Overall Security Score");
        markdownReport.Should().Contain("## Security Checks");
        markdownReport.Should().Contain("## Audit Statistics");
    }

    [Fact]
    public void SecurityScore_IsCalculated_Correctly()
    {
        // Arrange
        var reportGenerator = new MultiTenantSecurityReportGenerator();

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert
        report.OverallScore.Score.Should().BeGreaterThanOrEqualTo(0);
        report.OverallScore.Score.Should().BeLessThanOrEqualTo(100);
        report.OverallScore.Grade.Should().NotBeNullOrEmpty();
        report.OverallScore.Status.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void SecurityChecks_AllPass_WhenNoIssues()
    {
        // Arrange
        var reportGenerator = new MultiTenantSecurityReportGenerator();

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert
        report.SecurityChecks.TotalChecks.Should().BeGreaterThan(0);
        report.SecurityChecks.PassedChecks.Should().BeGreaterThanOrEqualTo(0);
        report.SecurityChecks.FailedChecks.Should().BeGreaterThanOrEqualTo(0);
        (report.SecurityChecks.PassedChecks + report.SecurityChecks.FailedChecks)
            .Should().Be(report.SecurityChecks.TotalChecks);
    }

    [Fact]
    public void AuditLogger_RecordsSuccess_Correctly()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<McpSecurityAuditLogger>>();
        var auditLogger = new McpSecurityAuditLogger(mockLogger.Object);

        var auditEvent = new McpSecurityAuditEvent
        {
            TenantId = Guid.NewGuid(),
            UserId = Guid.NewGuid(),
            Operation = "test_operation",
            Success = true
        };

        // Act
        auditLogger.LogSuccess(auditEvent);
        var stats = auditLogger.GetAuditStatistics();

        // Assert
        stats.TotalOperations.Should().Be(1);
        stats.SuccessfulOperations.Should().Be(1);
        stats.FailedOperations.Should().Be(0);
    }

    [Fact]
    public void AuditLogger_RecordsCrossTenantAttempt_Correctly()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<McpSecurityAuditLogger>>();
        var auditLogger = new McpSecurityAuditLogger(mockLogger.Object);

        var auditEvent = new McpSecurityAuditEvent
        {
            TenantId = Guid.NewGuid(),
            TargetTenantId = Guid.NewGuid(),
            UserId = Guid.NewGuid(),
            Operation = "cross_tenant_access",
            ResourceType = "projects",
            ResourceId = Guid.NewGuid()
        };

        // Act
        auditLogger.LogCrossTenantAccessAttempt(auditEvent);
        var stats = auditLogger.GetAuditStatistics();

        // Assert
        stats.CrossTenantAccessAttempts.Should().Be(1);
        stats.FailedOperations.Should().Be(1);
        stats.LastCrossTenantAttempt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
    }

    [Fact]
    public void TenantValidator_DetectsQueryWithTenantFilter()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<TenantContextValidator>>();
        var validator = new TenantContextValidator(mockLogger.Object);

        var queryWithFilter = "SELECT * FROM Projects WHERE TenantId = @tenantId";

        // Act
        var result = validator.ValidateQueryIncludesTenantFilter(queryWithFilter);
        var stats = validator.GetValidationStats();

        // Assert
        result.Should().BeTrue();
        stats.QueriesWithTenantFilter.Should().Be(1);
        stats.QueriesWithoutTenantFilter.Should().Be(0);
    }

    [Fact]
    public void TenantValidator_DetectsQueryWithoutTenantFilter()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<TenantContextValidator>>();
        var validator = new TenantContextValidator(mockLogger.Object);

        var queryWithoutFilter = "SELECT * FROM Projects WHERE Name = 'Test'";

        // Act
        var result = validator.ValidateQueryIncludesTenantFilter(queryWithoutFilter);
        var stats = validator.GetValidationStats();

        // Assert
        result.Should().BeFalse();
        stats.QueriesWithTenantFilter.Should().Be(0);
        stats.QueriesWithoutTenantFilter.Should().Be(1);
        stats.ViolatingQueries.Should().Contain(queryWithoutFilter);
    }

    [Fact]
    public void SecurityReport_IncludesFindings_ForCrossTenantAttempts()
    {
        // Arrange
        var mockLogger = new Mock<ILogger<McpSecurityAuditLogger>>();
        var auditLogger = new McpSecurityAuditLogger(mockLogger.Object);

        // Log a cross-tenant access attempt
        auditLogger.LogCrossTenantAccessAttempt(new McpSecurityAuditEvent
        {
            TenantId = Guid.NewGuid(),
            TargetTenantId = Guid.NewGuid()
        });

        var reportGenerator = new MultiTenantSecurityReportGenerator(auditLogger);

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert
        report.Findings.Should().NotBeEmpty();
        report.Findings.Should().Contain(f => f.Category.Contains("Cross-Tenant Access"));
    }

    [Fact]
    public void SecurityReport_IncludesFindings_ForUnfilteredQueries()
    {
        // Arrange
        var mockValidatorLogger = new Mock<ILogger<TenantContextValidator>>();
        var validator = new TenantContextValidator(mockValidatorLogger.Object);

        // Validate a query without tenant filter
        validator.ValidateQueryIncludesTenantFilter("SELECT * FROM Projects");

        var reportGenerator = new MultiTenantSecurityReportGenerator(tenantValidator: validator);

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert
        report.Findings.Should().NotBeEmpty();
        report.Findings.Should().Contain(f => f.Category.Contains("Queries Without TenantId Filter"));
        report.Findings.Should().Contain(f => f.Severity == "Critical");
    }

    [Fact]
    public void SecurityReport_ShowsPerfectScore_WhenNoIssues()
    {
        // Arrange
        var reportGenerator = new MultiTenantSecurityReportGenerator();

        // Act
        var report = reportGenerator.GenerateReport();

        // Assert - With no issues, should have high score
        report.OverallScore.Score.Should().BeGreaterThanOrEqualTo(90);
        report.OverallScore.Status.Should().BeOneOf("Pass", "Warning");
    }
}
