using System.Net;
using System.Text;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using SVSim.Database;
using SVSim.EmulatedEntrypoint;

namespace SVSim.UnitTests;

/// <summary>
/// Verifies the routing-prefix fix (audit step 5) actually exposes endpoints at the URLs the
/// client calls (no `api/` prefix). Posts plain JSON without UnityPlayer UA so the
/// translation middleware bypasses and we test routing in isolation.
/// </summary>
public class RoutingSmokeTests
{
    private sealed class TestFactory : WebApplicationFactory<Program>
    {
        protected override void ConfigureWebHost(Microsoft.AspNetCore.Hosting.IWebHostBuilder builder)
        {
            builder.ConfigureTestServices(services =>
            {
                var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<SVSimDbContext>));
                if (descriptor != null) services.Remove(descriptor);
                services.AddDbContext<SVSimDbContext>(opt => opt.UseInMemoryDatabase("RoutingSmoke"));
            });
        }
    }

    private const string ValidBaseRequestJson =
        """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""";

    [Test]
    public async Task CheckSpecialTitle_resolves_to_CheckController()
    {
        using var factory = new TestFactory();
        using var client = factory.CreateClient();

        var response = await client.PostAsync("/check/special_title",
            new StringContent(ValidBaseRequestJson, Encoding.UTF8, "application/json"));

        Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK),
            $"Expected 200 OK at /check/special_title, got {response.StatusCode}. " +
            "If 404, the routing prefix fix (audit step 5) didn't take.");

        var body = await response.Content.ReadAsStringAsync();
        // Plain-JSON path uses camelCase (System.Text.Json default); MessagePack [Key] only applies
        // to the Unity-UA encrypted path through ShadowverseTranslationMiddleware.
        Assert.That(body, Does.Contain("\"title_image_id\":\"0\""),
            "SpecialTitleCheck should return the built-in title id \"0\".");
    }

    [Test]
    public async Task ImportViewer_route_resolves()
    {
        // /admin/import_viewer is AllowAnonymous so the route should at least be reachable
        // (probably returns 400 for missing steam_id with our empty BaseRequest body; we only
        // assert routing not deep behavior).
        using var factory = new TestFactory();
        using var client = factory.CreateClient();

        var response = await client.PostAsync("/admin/import_viewer",
            new StringContent(ValidBaseRequestJson, Encoding.UTF8, "application/json"));

        Assert.That(response.StatusCode, Is.Not.EqualTo(HttpStatusCode.NotFound),
            "/admin/import_viewer didn't resolve to a controller — route registration broken.");
    }

    [Test]
    public async Task ApiPrefixedRoute_returns_404()
    {
        // The OLD broken path should now 404 — proves we dropped the `api/` prefix cleanly.
        using var factory = new TestFactory();
        using var client = factory.CreateClient();

        var response = await client.PostAsync("/api/check/special_title",
            new StringContent(ValidBaseRequestJson, Encoding.UTF8, "application/json"));

        Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
    }

    // Authenticated endpoints — we don't set up Steam auth in tests, so we just assert the
    // route resolves (anything other than 404). Auth-flow integration tests are a separate
    // problem — see PLAN.md status-log open item on body re-read.

    [TestCase("/practice/info")]
    [TestCase("/practice/deck_list")]
    [TestCase("/practice/start")]
    [TestCase("/practice/finish")]
    [TestCase("/deck/my_list")]
    [TestCase("/deck/info")]
    [TestCase("/deck/update")]
    [TestCase("/deck/update_name")]
    [TestCase("/deck/update_sleeve")]
    [TestCase("/deck/update_leader_skin")]
    [TestCase("/deck/update_random_leader_skin")]
    [TestCase("/deck/update_order")]
    [TestCase("/deck/delete_deck_list")]
    [TestCase("/deck/get_empty_deck_number")]
    [TestCase("/deck/set_deck_redis")]
    [TestCase("/arena_two_pick/top")]
    [TestCase("/arena_two_pick/entry")]
    [TestCase("/arena_two_pick/class_choose")]
    [TestCase("/arena_two_pick/card_choose")]
    [TestCase("/arena_two_pick/retire")]
    [TestCase("/arena_two_pick/finish")]
    [TestCase("/arena_two_pick_battle/do_matching")]
    [TestCase("/arena_two_pick_battle/finish")]
    [TestCase("/arena_colosseum/get_fee_info")]
    [TestCase("/arena/get_challenge_info")]
    [TestCase("/arena/get_challenge_ranking_history")]
    [TestCase("/check/check_time_slip_card_master_hash")]
    [TestCase("/rotation_rank_battle/do_matching")]
    [TestCase("/unlimited_rank_battle/do_matching")]
    [TestCase("/ai_rotation_rank_battle/start")]
    [TestCase("/ai_unlimited_rank_battle/start")]
    [TestCase("/rotation_rank_battle/finish")]
    [TestCase("/unlimited_rank_battle/finish")]
    [TestCase("/ai_rotation_rank_battle/finish")]
    [TestCase("/ai_unlimited_rank_battle/finish")]
    [TestCase("/rank_battle/force_finish")]
    [TestCase("/rank_battle/add_client_log")]
    [TestCase("/rank_battle/add_all_client_log")]
    [TestCase("/rank_battle/add_last_turn_log")]
    [TestCase("/rank_battle/get_latest_master_point")]
    public async Task Authenticated_route_resolves(string path)
    {
        using var factory = new TestFactory();
        using var client = factory.CreateClient();

        var response = await client.PostAsync(path,
            new StringContent(ValidBaseRequestJson, Encoding.UTF8, "application/json"));

        Assert.That(response.StatusCode, Is.Not.EqualTo(HttpStatusCode.NotFound),
            $"{path} didn't resolve to a controller — route registration broken.");
    }
}
