using Dapper;
using KArtSell.Host.Observability;
using Npgsql;
using Xunit;

namespace KArtSell.Integration.Tests;

[Collection("Database")]
public class OpenDartServiceTests : IAsyncLifetime
{
    private readonly NpgsqlDataSource _dataSource;
    private readonly OpenDartService _service;

    public OpenDartServiceTests(DatabaseFixture fixture)
    {
        _dataSource = fixture.DataSource;
        // Set test API key to stub/test mode (AGENTS.md §9: reproducibility, external dependency isolation)
        // Tests must NOT call real APIs; configure for local testing only
        if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("OPENDART_API")))
            Environment.SetEnvironmentVariable("OPENDART_API", "test-stub-key-no-real-calls");

        // Use HttpClient without network to prevent real API calls in tests
        // Real API calls belong in shadow run, not unit/integration tests
        _service = new OpenDartService(_dataSource, new HttpClient(), fixture.Clock(), fixture.Logger<OpenDartService>());
    }

    public async Task InitializeAsync()
    {
        // Create opendata schema if needed
        await using var conn = await _dataSource.OpenConnectionAsync();
        await conn.ExecuteAsync("""
            CREATE SCHEMA IF NOT EXISTS opendata;
            CREATE TABLE IF NOT EXISTS opendata.opendart_cache (
                id BIGSERIAL PRIMARY KEY,
                ticker VARCHAR(10) NOT NULL,
                quarter VARCHAR(6) NOT NULL,
                data_json JSONB NOT NULL,
                expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
                published_at TIMESTAMP WITH TIME ZONE NOT NULL,
                UNIQUE(ticker, quarter)
            );
            TRUNCATE opendata.opendart_cache;
            """);
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task OpenDartCache_SchemaExists()
    {
        // Verify opendata schema and tables exist
        await using var conn = await _dataSource.OpenConnectionAsync();

        var schemaExists = await conn.QueryFirstOrDefaultAsync<bool>(
            "SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name = 'opendata')");
        Assert.True(schemaExists, "opendata schema should exist");

        var cacheTableExists = await conn.QueryFirstOrDefaultAsync<bool>(
            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'opendata' AND table_name = 'opendart_cache')");
        Assert.True(cacheTableExists, "opendata.opendart_cache table should exist");
    }

    [Fact]
    public async Task OpenDartCache_HasRequiredColumns()
    {
        await using var conn = await _dataSource.OpenConnectionAsync();

        var columnNames = await conn.QueryAsync<string>("""
            SELECT column_name
            FROM information_schema.columns
            WHERE table_schema = 'opendata' AND table_name = 'opendart_cache'
            ORDER BY ordinal_position
            """);

        var cols = columnNames.ToList();
        Assert.Contains("ticker", cols);
        Assert.Contains("quarter", cols);
        Assert.Contains("data_json", cols);
        Assert.Contains("expires_at", cols);
    }

    [Fact]
    public async Task OpenDartBatchLog_SchemaExists()
    {
        await using var conn = await _dataSource.OpenConnectionAsync();

        var batchLogExists = await conn.QueryFirstOrDefaultAsync<bool>(
            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'opendata' AND table_name = 'opendart_batch_log')");
        Assert.True(batchLogExists, "opendata.opendart_batch_log table should exist");
    }
}
