using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using Microsoft.Extensions.Logging.Abstractions;
using FeedserXmlSchemaValidator = StellaOps.Feedser.Source.Common.Xml.XmlSchemaValidator;
using FeedserXmlSchemaValidationException = StellaOps.Feedser.Source.Common.Xml.XmlSchemaValidationException;

namespace StellaOps.Feedser.Source.Common.Tests.Xml;

public sealed class XmlSchemaValidatorTests
{
    private static XmlSchemaSet CreateSchema()
    {
        var set = new XmlSchemaSet();
        set.Add(string.Empty, XmlReader.Create(new StringReader("""
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
              <xs:element name="root">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="id" type="xs:string" />
                    <xs:element name="count" type="xs:int" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:schema>
            """)));
        set.CompilationSettings = new XmlSchemaCompilationSettings { EnableUpaCheck = true };
        set.Compile();
        return set;
    }

    [Fact]
    public void Validate_AllowsCompliantDocument()
    {
        var schemaSet = CreateSchema();
        var document = XDocument.Parse("<root><id>abc</id><count>3</count></root>");
        var validator = new FeedserXmlSchemaValidator(NullLogger<FeedserXmlSchemaValidator>.Instance);

        var exception = Record.Exception(() => validator.Validate(document, schemaSet, "valid.xml"));

        Assert.Null(exception);
    }

    [Fact]
    public void Validate_ThrowsWithDetailedErrors()
    {
        var schemaSet = CreateSchema();
        var document = XDocument.Parse("<root><id>missing-count</id></root>");
        var validator = new FeedserXmlSchemaValidator(NullLogger<FeedserXmlSchemaValidator>.Instance);

        var ex = Assert.Throws<FeedserXmlSchemaValidationException>(() => validator.Validate(document, schemaSet, "invalid.xml"));

        Assert.Equal("invalid.xml", ex.DocumentName);
        Assert.NotEmpty(ex.Errors);
        Assert.Contains(ex.Errors, error => error.Message.Contains("count", StringComparison.OrdinalIgnoreCase));
    }
}
