using System.Net;
using System.Net.Http.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Nalu.Web.Models;
using Xunit;

namespace Nalu.Tests;

/// <summary>
/// Integration tests using WebApplicationFactory.
/// The Validators directory must be available in the test output — the .csproj
/// CopyToOutputDirectory on the main project handles this via project reference.
/// </summary>
public class PipelineIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;

    public PipelineIntegrationTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
        _client.DefaultRequestHeaders.Add("Authorization", "Bearer nalu-test-key-001");
    }

    // ── Auth ──────────────────────────────────────────────────────────────────

    [Fact]
    public async Task NoApiKey_Returns401()
    {
        using var client = new HttpClient { BaseAddress = _client.BaseAddress };
        var response = await client.PostAsJsonAsync("/v1/extract/name", new
        {
            agent_input = "Qual seu nome?",
            user_input = "João"
        });

        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
    }

    [Fact]
    public async Task InvalidApiKey_Returns401()
    {
        using var client = new HttpClient { BaseAddress = _client.BaseAddress };
        client.DefaultRequestHeaders.Add("Authorization", "Bearer invalid-key");
        var response = await client.PostAsJsonAsync("/v1/extract/name", new
        {
            agent_input = "Qual seu nome?",
            user_input = "João"
        });

        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
    }

    // ── Name extraction — deterministic path ──────────────────────────────────

    [Fact]
    public async Task PostName_WithGreeting_ReturnsObtainedFalse()
    {
        var response = await PostExtractName("Qual seu nome completo?", "Bom dia!");

        response.Should().NotBeNull();
        response!.Obtained.Should().BeFalse();
        response.Certain.Should().BeFalse();
        response.ExtractedValue.Should().BeNull();
        response.SuggestionToAgent.Should().Contain("Bom dia!");
    }

    [Fact]
    public async Task PostName_WithAcceptPattern_ReturnsObtainedTrue()
    {
        var response = await PostExtractName("Qual seu nome?", "meu nome é Carlos Silva");

        response.Should().NotBeNull();
        response!.Obtained.Should().BeTrue();
        response.Certain.Should().BeTrue();
        response.ExtractedValue.Should().Be("Carlos Silva");
        response.Confidence.Should().Be("high");
    }

    [Fact]
    public async Task PostName_RejectPattern_ReturnsObtainedFalse()
    {
        var response = await PostExtractName("Qual seu nome?", "sei la");

        response.Should().NotBeNull();
        response!.Obtained.Should().BeFalse();
    }

    // ── GET /v1/validators ────────────────────────────────────────────────────

    [Fact]
    public async Task GetValidators_ReturnsValidatorList()
    {
        var result = await _client.GetFromJsonAsync<ValidatorsResponse>("/v1/validators");

        result.Should().NotBeNull();
        result!.Validators.Should().NotBeEmpty();
        result.Validators.Should().Contain(v => v.Id == "validate_full_name");

        var nameValidator = result.Validators.First(v => v.Id == "validate_full_name");
        nameValidator.Endpoint.Should().Be("/v1/extract/name");
        nameValidator.McpTool.Should().Be("nalu_extract_name");
        nameValidator.Languages.Should().Contain("pt-BR");
    }

    // ── Response structure ────────────────────────────────────────────────────

    [Fact]
    public async Task PostName_ResponseContainsAllRequiredFields()
    {
        var response = await PostExtractName("Qual seu nome?", "Bom dia!");

        response.Should().NotBeNull();
        response!.Obtained.Should().BeFalse(); // greeting → not obtained
        response.Confidence.Should().BeOneOf("high", "medium", "low");
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    private async Task<ExtractionResponse?> PostExtractName(string agentInput, string userInput)
    {
        var payload = new ExtractionRequest
        {
            AgentInput = agentInput,
            UserInput = userInput,
            Language = "pt-BR"
        };

        var httpResponse = await _client.PostAsJsonAsync("/v1/extract/name", payload);
        httpResponse.EnsureSuccessStatusCode();
        return await httpResponse.Content.ReadFromJsonAsync<ExtractionResponse>();
    }

    private record ValidatorsResponse(List<ValidatorInfo> Validators);
}
