"""T-INV-P-001…007 — the paste-block format ports (byte-format is the
contract; the fixtures carry 1:1 from work/tests/invoices.test.ts) —
plus T-INV-P-002's rebuild amendment: the three business literals are
TENANT SETTINGS, not code literals. And the T-INV-D date-default
pytest twins (the vitest ports live in frontend lib/invoices.test.ts)."""

from datetime import date

from app.services.money.invoices import (
    clean_status,
    default_invoice_date,
    parse_invoice_date,
    parse_manual_total,
)
from app.services.money.paste_block import (
    PasteBlockConfig,
    format_paste_block,
    paste_block_config,
)

DATE = "2026-04-30"


def row(client, project, amount):
    return {
        "client": client,
        "project": project,
        "summed_billout": {"amount": amount, "currency": "CAD"},
    }


class TestPasteBlockFormat:
    def test_inv_p_001_empty_breakdown_renders_empty_string(self):
        assert format_paste_block([], DATE) == ""

    def test_inv_p_002_one_line_seven_tab_separated_columns(self):
        out = format_paste_block([row("DaxTech", "Website", "75.00")], DATE)
        assert out.split("\t") == [
            "DaxTech : Website",
            "Bowden Works Team",
            "75.00",
            "2026-04-30",
            "",
            "Bowden Works",
            "Labour",
        ]

    def test_inv_p_002_amendment_literals_are_tenant_settings(self):
        cfg = paste_block_config(
            {
                "paste_block": {
                    "team_label": "Acme Crew",
                    "operator_label": "Acme",
                    "category_label": "Consulting",
                }
            }
        )
        out = format_paste_block([row("C", "P", "5.00")], DATE, cfg)
        cols = out.split("\t")
        assert cols[1] == "Acme Crew"
        assert cols[5] == "Acme"
        assert cols[6] == "Consulting"
        # absent settings -> the Bowden Works tenant's values
        assert paste_block_config(None) == PasteBlockConfig()
        assert paste_block_config({"default_currency": "CAD"}) == PasteBlockConfig()

    def test_inv_p_003_amount_two_decimals_no_symbol(self):
        out = format_paste_block([row("C", "P", "1234.5")], DATE)
        assert "\t1234.50\t" in out
        assert "$" not in out

    def test_inv_p_004_rows_join_with_newlines_caller_order_preserved(self):
        out = format_paste_block(
            [row("B", "Beta", "20.00"), row("A", "Alpha", "10.00")], DATE
        )
        lines = out.split("\n")
        assert len(lines) == 2
        assert lines[0].startswith("B : Beta\t")  # no sort here (B44 sorts upstream)
        assert lines[1].startswith("A : Alpha\t")

    def test_inv_p_005_null_client_project_literals(self):
        out = format_paste_block([row(None, None, "5.00")], DATE)
        assert out.split("\t")[0] == "(no client) : (no project)"

    def test_inv_p_006_colon_with_spaces_separator(self):
        out = format_paste_block([row("C", "P", "5.00")], DATE)
        assert out.startswith("C : P\t")

    def test_inv_p_007_fifth_column_is_empty(self):
        out = format_paste_block([row("C", "P", "5.00")], DATE)
        assert out.split("\t")[4] == ""


class TestDefaultInvoiceDate:
    def test_inv_d_001_mid_month(self):
        assert default_invoice_date(date(2026, 5, 15)) == date(2026, 4, 30)

    def test_inv_d_002_first_of_month(self):
        assert default_invoice_date(date(2026, 6, 1)) == date(2026, 5, 31)

    def test_inv_d_003_january_rolls_to_previous_december(self):
        assert default_invoice_date(date(2026, 1, 10)) == date(2025, 12, 31)

    def test_inv_d_004_leap_year_february(self):
        assert default_invoice_date(date(2024, 3, 5)) == date(2024, 2, 29)
        assert default_invoice_date(date(2026, 3, 5)) == date(2026, 2, 28)


class TestFieldParsers:
    def test_invoice_date_calendar_validated(self):
        assert parse_invoice_date("2026-04-30") == date(2026, 4, 30)
        # the legacy regex let 2026-99-99 through to a raw PG error (B4
        # wart); the rebuild treats it as malformed
        assert parse_invoice_date("2026-99-99") is None
        assert parse_invoice_date("") is None
        assert parse_invoice_date("nope") is None
        assert parse_invoice_date(None) is None

    def test_status_coercion(self):
        assert clean_status(" Sent ") == "sent"
        assert clean_status("PAID") == "paid"
        assert clean_status("draft") == "open"
        assert clean_status(None) == "open"

    def test_manual_total_parse_money_or_null(self):
        assert str(parse_manual_total("5000")) == "5000.00"
        assert str(parse_manual_total("12.345")) == "12.35"  # 2dp half-up
        assert parse_manual_total("") is None
        assert parse_manual_total("  ") is None
        assert parse_manual_total("abc") is None
        assert parse_manual_total(None) is None
