using AccountTracking.Api.Data;
using AccountTracking.Api.Services;
using Microsoft.EntityFrameworkCore;

namespace AccountTracking.Api.Tests;

public class CsvImportServiceTests
{
    private static AppDbContext CreateDb()
    {
        var opts = new DbContextOptionsBuilder<AppDbContext>()
            .UseInMemoryDatabase(Guid.NewGuid().ToString())
            .Options;
        return new AppDbContext(opts);
    }

    private static CsvImportService CreateService(AppDbContext db)
        => new(db);

    // Minimal valid CSV with two data rows
    private const string ValidCsv = """
        Pohyby na účtu 216868554/0300 dne 19.03.2026

        číslo účtu;datum zaúčtování;částka;měna;zůstatek;číslo protiúčtu;kód banky protiúčtu;jméno protistrany;adresa protistrany;konstantní symbol;variabilní symbol;specifický symbol;označení operace;název trálého příkazu;vlastní poznámka;zpráva;kategorie;původní transakce;kurz;E2E identifikace;reference plátce;původní plátce;konečný příjemce;ID transakce
        216868554/0300;15.03.2026;-1 740,80;CZK;93 346,57;;;;;;205000001;;Transakce platební kartou;;;Zpráva 1;Potraviny;;;;;;;tx-001
        216868554/0300;14.03.2026;-800,00;CZK;95 087,37;;;;;;205000002;;Transakce platební kartou;;;Zpráva 2;Restaurace;;;;;;;tx-002
        """;

    private const string CsvMissingHeader = """
        Pohyby na účtu
        Nějaky obsah bez správné hlavičky
        datum;částka
        """;

    private const string CsvMissingRequiredColumn = """
        číslo účtu;datum zaúčtování;měna;zůstatek;ID transakce
        216868554/0300;15.03.2026;CZK;93346,57;tx-001
        """;

    [Fact]
    public async Task Import_ParsesRowsCorrectly()
    {
        using var db = CreateDb();
        var svc = CreateService(db);

        var result = await svc.ImportAsync(ValidCsv, "test.csv");

        Assert.True(result.IsSuccess);
        Assert.Equal(2, result.Value!.RecordsImported);
        Assert.Equal(0, result.Value.RecordsSkipped);

        var transactions = await db.Transactions.ToListAsync();
        Assert.Equal(2, transactions.Count);

        var tx = transactions.First(t => t.TransactionId == "tx-001");
        Assert.Equal(-1740.80m, tx.Amount);
        Assert.Equal(93346.57m, tx.Balance);
        Assert.Equal("Potraviny", tx.Category);
        Assert.Equal(new DateOnly(2026, 3, 15), tx.BookingDate);
    }

    [Fact]
    public async Task Import_SkipsDuplicateTransactionIds()
    {
        using var db = CreateDb();
        var svc = CreateService(db);

        await svc.ImportAsync(ValidCsv, "first.csv");
        var result = await svc.ImportAsync(ValidCsv, "second.csv");

        Assert.True(result.IsSuccess);
        Assert.Equal(0, result.Value!.RecordsImported);
        Assert.Equal(2, result.Value.RecordsSkipped);
        Assert.Equal(2, await db.Transactions.CountAsync());
    }

    [Fact]
    public async Task Import_FindsHeaderByScanning_NotByLineNumber()
    {
        // Header is on line 3 in ValidCsv — but we scan, not hardcode
        using var db = CreateDb();
        var svc = CreateService(db);

        var result = await svc.ImportAsync(ValidCsv, "test.csv");

        Assert.True(result.IsSuccess);
    }

    [Fact]
    public async Task Import_ReturnsError_WhenHeaderNotFound()
    {
        using var db = CreateDb();
        var svc = CreateService(db);

        var result = await svc.ImportAsync(CsvMissingHeader, "bad.csv");

        Assert.False(result.IsSuccess);
        Assert.Contains("hlavičku", result.Error, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public async Task Import_ReturnsError_WhenRequiredColumnMissing()
    {
        using var db = CreateDb();
        var svc = CreateService(db);

        var result = await svc.ImportAsync(CsvMissingRequiredColumn, "bad.csv");

        Assert.False(result.IsSuccess);
        Assert.Contains("částka", result.Error, StringComparison.OrdinalIgnoreCase);
    }

    [Theory]
    [InlineData("1 740,80", 1740.80)]
    [InlineData("-4 263,15", -4263.15)]
    [InlineData("-800,00", -800.00)]
    [InlineData("93 346,57", 93346.57)]
    public void ParseAmount_HandlesChechLocaleFormat(string input, decimal expected)
    {
        var result = CsvImportService.ParseCzechDecimal(input);
        Assert.Equal(expected, result);
    }
}
