using FluentValidation.TestHelper;
using Microsoft.Extensions.Options;
using SatelliteProvider.Api.Validators;
using SatelliteProvider.Common.Configs;
using SatelliteProvider.Common.DTO;

namespace SatelliteProvider.Tests.Validators;

// AZ-810: root metadata-envelope validator tests. Covers `items` non-null +
// non-empty + cap rules. The per-item rules are covered by UavTileMetadataValidatorTests.
public class UavTileBatchMetadataPayloadValidatorTests
{
    private readonly UavTileBatchMetadataPayloadValidator _validator;
    private readonly DateTime _now;

    public UavTileBatchMetadataPayloadValidatorTests()
    {
        GlobalValidatorConfig.ApplyOnce();
        var config = Options.Create(new UavQualityConfig
        {
            MaxBatchSize = 100,
            MaxAgeDays = 7,
            CapturedAtFutureSkewSeconds = 30,
        });
        _now = new DateTime(2026, 5, 22, 12, 0, 0, DateTimeKind.Utc);
        _validator = new UavTileBatchMetadataPayloadValidator(config, new FixedTimeProvider(_now));
    }

    private UavTileMetadata ValidItem() => new()
    {
        Latitude = 50.10,
        Longitude = 36.10,
        TileZoom = 18,
        TileSizeMeters = 200.0,
        CapturedAt = _now.AddMinutes(-5),
        FlightId = null,
    };

    [Fact]
    public void Validate_OneValidItem_Passes()
    {
        // Arrange
        var payload = new UavTileBatchMetadataPayload { Items = new() { ValidItem() } };

        // Act
        var result = _validator.TestValidate(payload);

        // Assert
        result.ShouldNotHaveAnyValidationErrors();
    }

    [Fact]
    public void Validate_ItemsEmpty_FailsNotEmptyRule()
    {
        // Arrange
        var payload = new UavTileBatchMetadataPayload { Items = new() };

        // Act
        var result = _validator.TestValidate(payload);

        // Assert
        result.ShouldHaveValidationErrorFor("items")
            .WithErrorMessage("`items` must contain at least one entry.");
    }

    [Fact]
    public void Validate_ItemsTooMany_FailsCountRule()
    {
        // Arrange — 101 items (cap = 100)
        var items = Enumerable.Range(0, 101).Select(_ => ValidItem()).ToList();
        var payload = new UavTileBatchMetadataPayload { Items = items };

        // Act
        var result = _validator.TestValidate(payload);

        // Assert
        result.ShouldHaveValidationErrorFor("items")
            .WithErrorMessage("`items` must contain at most 100 entries.");
    }

    [Fact]
    public void Validate_PerItemFailure_PropagatesWithIndexedPath()
    {
        // Arrange — first item valid, second item lat out-of-range
        var payload = new UavTileBatchMetadataPayload
        {
            Items = new() { ValidItem(), ValidItem() with { Latitude = 91.0 } },
        };

        // Act
        var result = _validator.TestValidate(payload);

        // Assert — error key follows the wire format produced by RuleForEach.
        result.ShouldHaveValidationErrorFor("items[1].latitude");
    }

    private sealed class FixedTimeProvider : TimeProvider
    {
        private readonly DateTime _utcNow;
        public FixedTimeProvider(DateTime utcNow) => _utcNow = utcNow;
        public override DateTimeOffset GetUtcNow() => new(_utcNow, TimeSpan.Zero);
    }
}
