using System.Text.Json;
using StellaOps.Scanner.Core.Contracts;
using StellaOps.Scanner.Core.Serialization;
using StellaOps.Scanner.Core.Utility;
using Xunit;

namespace StellaOps.Scanner.Core.Tests.Contracts;

public sealed class ScanJobTests
{
    [Fact]
    public void SerializeAndDeserialize_RoundTripsDeterministically()
    {
        var createdAt = new DateTimeOffset(2025, 10, 18, 14, 30, 15, TimeSpan.Zero);
        var jobId = ScannerIdentifiers.CreateJobId("registry.example.com/stellaops/scanner:1.2.3", "sha256:ABCDEF", "tenant-a", "request-1");
        var correlationId = ScannerIdentifiers.CreateCorrelationId(jobId, "enqueue");
        var error = new ScannerError(
            ScannerErrorCode.AnalyzerFailure,
            ScannerErrorSeverity.Error,
            "Analyzer crashed for layer sha256:abc",
            createdAt,
            retryable: false,
            details: new Dictionary<string, string>
            {
                ["stage"] = "analyze-os",
                ["layer"] = "sha256:abc"
            });

        var job = new ScanJob(
            jobId,
            ScanJobStatus.Running,
            "registry.example.com/stellaops/scanner:1.2.3",
            "SHA256:ABCDEF",
            createdAt,
            createdAt,
            correlationId,
            "tenant-a",
            new Dictionary<string, string>
            {
                ["requestId"] = "request-1"
            },
            error);

        var json = JsonSerializer.Serialize(job, ScannerJsonOptions.CreateDefault());
        var deserialized = JsonSerializer.Deserialize<ScanJob>(json, ScannerJsonOptions.CreateDefault());

        Assert.NotNull(deserialized);
        Assert.Equal(job.Id, deserialized!.Id);
        Assert.Equal(job.ImageDigest, deserialized.ImageDigest);
        Assert.Equal(job.CorrelationId, deserialized.CorrelationId);
        Assert.Equal(job.Metadata["requestId"], deserialized.Metadata["requestId"]);

        var secondJson = JsonSerializer.Serialize(deserialized, ScannerJsonOptions.CreateDefault());
        Assert.Equal(json, secondJson);
    }

    [Fact]
    public void WithStatus_UpdatesTimestampDeterministically()
    {
        var createdAt = new DateTimeOffset(2025, 10, 18, 14, 30, 15, 123, TimeSpan.Zero);
        var jobId = ScannerIdentifiers.CreateJobId("example/scanner:latest", "sha256:def", null, null);
        var correlationId = ScannerIdentifiers.CreateCorrelationId(jobId, "enqueue");

        var job = new ScanJob(
            jobId,
            ScanJobStatus.Pending,
            "example/scanner:latest",
            "sha256:def",
            createdAt,
            null,
            correlationId,
            null,
            null,
            null);

        var updated = job.WithStatus(ScanJobStatus.Running, createdAt.AddSeconds(5));

        Assert.Equal(ScanJobStatus.Running, updated.Status);
        Assert.Equal(ScannerTimestamps.Normalize(createdAt.AddSeconds(5)), updated.UpdatedAt);
    }
}
