"""CSV/TSV transaction parser tests.

Fixture: tests/fixtures/homedepot.csv
Source:  Home Depot TSV export (no header, tab-separated, UTF-8 BOM)
"""
import io
from decimal import Decimal
from datetime import date

import pytest

from app.services.csv_parser import parse_csv

HD_FIXTURE = "tests/fixtures/homedepot.csv"


class TestHomDepotFixture:
    def test_no_errors(self):
        result = parse_csv(HD_FIXTURE)
        assert result.errors == []

    def test_transaction_count(self):
        result = parse_csv(HD_FIXTURE)
        assert len(result.transactions) == 2

    def test_row_count(self):
        result = parse_csv(HD_FIXTURE)
        assert result.row_count == 2

    def test_merchant_normalized_to_home_depot(self):
        result = parse_csv(HD_FIXTURE)
        for t in result.transactions:
            assert t.merchant_normalized == "Home Depot"

    def test_amounts(self):
        result = parse_csv(HD_FIXTURE)
        amounts = sorted(t.amount for t in result.transactions)
        assert amounts == [Decimal("839.20"), Decimal("1047.00")]

    def test_dates(self):
        result = parse_csv(HD_FIXTURE)
        dates = sorted(t.date for t in result.transactions)
        assert dates == [date(2026, 5, 18), date(2026, 5, 26)]

    def test_purchases_not_credits(self):
        result = parse_csv(HD_FIXTURE)
        for t in result.transactions:
            assert t.is_credit is False

    def test_dedup_hashes_unique(self):
        result = parse_csv(HD_FIXTURE)
        hashes = [t.dedup_hash for t in result.transactions]
        assert len(set(hashes)) == 2

    def test_confidence_is_1(self):
        result = parse_csv(HD_FIXTURE)
        for t in result.transactions:
            assert t.confidence_score == 1.0


class TestCsvParserGeneric:
    def _make_csv(self, content: str, bom: bool = False) -> io.BytesIO:
        if bom:
            content = "﻿" + content
        return io.BytesIO(content.encode("utf-8"))

    def test_comma_separated(self):
        csv = self._make_csv(
            "date,description,amount,type\n"
            "2026-01-15,Starbucks,5.50,purchase\n"
        )
        result = parse_csv(csv)
        assert len(result.transactions) == 1
        assert result.transactions[0].merchant_normalized == "Starbucks"
        assert result.transactions[0].amount == Decimal("5.50")

    def test_tab_separated(self):
        tsv = self._make_csv("2026-02-01\t$29.99\tNetflix\tpurchase\n")
        result = parse_csv(tsv)
        assert len(result.transactions) == 1
        assert result.transactions[0].merchant_normalized == "Netflix"
        assert result.transactions[0].amount == Decimal("29.99")

    def test_dollar_sign_stripped_from_amount(self):
        csv = self._make_csv(
            "date,amount,description\n"
            "2026-03-10,$45.00,Amazon\n"
        )
        result = parse_csv(csv)
        assert result.transactions[0].amount == Decimal("45.00")

    def test_negative_amount_is_credit(self):
        csv = self._make_csv(
            "date,amount,description,type\n"
            "2026-01-20,-15.00,Refund,credit\n"
        )
        result = parse_csv(csv)
        assert result.transactions[0].is_credit is True
        assert result.transactions[0].amount == Decimal("15.00")

    def test_credit_type_marks_is_credit(self):
        csv = self._make_csv(
            "date,amount,description,type\n"
            "2026-01-20,15.00,Payment,payment\n"
        )
        result = parse_csv(csv)
        assert result.transactions[0].is_credit is True

    def test_blank_rows_skipped(self):
        csv = self._make_csv(
            "date,description,amount\n"
            "2026-01-10,Coffee,3.50\n"
            "\n"
            "2026-01-11,Tea,2.50\n"
        )
        result = parse_csv(csv)
        assert len(result.transactions) == 2

    def test_utf8_bom_handled(self):
        tsv = self._make_csv("2026-01-01\t$10.00\tShop\tpurchase\n", bom=True)
        result = parse_csv(tsv)
        assert len(result.transactions) == 1

    def test_date_format_slash(self):
        csv = self._make_csv(
            "date,description,amount\n"
            "05/15/2026,Walmart,22.50\n"
        )
        result = parse_csv(csv)
        assert result.transactions[0].date == date(2026, 5, 15)

    def test_date_format_iso(self):
        csv = self._make_csv(
            "date,description,amount\n"
            "2026-07-04,Target,18.99\n"
        )
        result = parse_csv(csv)
        assert result.transactions[0].date == date(2026, 7, 4)

    def test_no_header_autodetect(self):
        tsv = self._make_csv("05/26/2026\t$50.00\tCostco\tpurchase\n")
        result = parse_csv(tsv)
        assert len(result.transactions) == 1
        assert result.transactions[0].amount == Decimal("50.00")

    def test_issuer_assigned(self):
        tsv = self._make_csv("2026-01-01\t$5.00\tTest Merchant\tpurchase\n")
        result = parse_csv(tsv, issuer="my_bank")
        assert result.transactions[0].issuer == "my_bank"

    def test_empty_file_returns_empty(self):
        result = parse_csv(io.BytesIO(b""))
        assert result.transactions == []
        assert result.errors == []
