using AgentSmith.Application.Models;
using AgentSmith.Contracts.Commands;
using AgentSmith.Contracts.Models;
using AgentSmith.Contracts.Providers;
using AgentSmith.Contracts.Sandbox;
using AgentSmith.Domain.Entities;
using AgentSmith.Domain.Models;
using Microsoft.Extensions.Logging;

namespace AgentSmith.Application.Services.Handlers;

/// <summary>
/// Runs static regex-based pattern scanning against repository source files.
/// Stores the result in the pipeline context for downstream triage.
/// </summary>
public sealed class StaticPatternScanHandler(
    IStaticPatternScanner scanner,
    ISandboxFileReaderFactory readerFactory,
    ILogger<StaticPatternScanHandler> logger)
    : ICommandHandler<StaticPatternScanContext>
{
    public async Task<CommandResult> ExecuteAsync(
        StaticPatternScanContext context, CancellationToken cancellationToken)
    {
        if (!context.Pipeline.TryGet<Repository>(ContextKeys.Repository, out var repo)
            || repo is null)
        {
            logger.LogInformation("No repository available, skipping static pattern scan");
            return CommandResult.Ok("No repository available, skipping static scan");
        }

        var sandbox = context.Pipeline.Get<ISandbox>(ContextKeys.Sandbox);
        var reader = readerFactory.Create(sandbox);
        var result = await scanner.ScanAsync(reader, cancellationToken);
        context.Pipeline.Set(ContextKeys.StaticScanResult, result);

        var observations = result.Findings.Select(f => new SkillObservation(
            Id: 0, Role: "static-pattern-scanner",
            Concern: ObservationConcern.Security,
            Description: f.Title,
            Suggestion: "",
            Blocking: false,
            Severity: ScannerObservationFactory.ParseSeverity(f.Severity, logger),
            Confidence: f.Confidence * 10,
            Rationale: f.Description,
            File: f.File, StartLine: f.Line,
            EvidenceMode: EvidenceMode.AnalyzedFromSource,
            Category: f.Category)).ToList();
        ScannerObservationFactory.AppendObservations(context.Pipeline, observations);

        var findings = result.Findings;
        var critical = findings.Count(f => f.Severity.Equals("critical", StringComparison.OrdinalIgnoreCase));
        var high = findings.Count(f => f.Severity.Equals("high", StringComparison.OrdinalIgnoreCase));
        var medium = findings.Count(f => f.Severity.Equals("medium", StringComparison.OrdinalIgnoreCase));
        var low = findings.Count - critical - high - medium;

        logger.LogInformation(
            "Static scan complete: {Findings} findings in {Files} files ({Patterns} patterns) in {Duration}ms — {Critical}C/{High}H/{Medium}M/{Low}L",
            findings.Count, result.FilesScanned, result.PatternsApplied, result.DurationMilliseconds,
            critical, high, medium, low);

        return CommandResult.Ok(
            $"Static scan: {findings.Count} findings ({critical}C/{high}H/{medium}M/{low}L) in {result.FilesScanned} files");
    }
}
