"""Unit tests: variable engine, invoice numbers, random financial generators."""
import string

import pytest

from app.services.variable_engine import (
    GeneratedValues,
    VariableEngine,
    analyze_template_variables,
)


class TestInvoiceGeneration:
    def test_default_format_shape(self):
        ve = VariableEngine()
        inv = ve.generate_invoice_number()
        assert inv.startswith("INV-")
        # {R4}-{R5}-{R6}-{seq4}: total = 4+1+5+1+6+1+4 = 22 chars
        assert len(inv) == len("INV-") + 22
        parts = inv[len("INV-"):].split("-")
        assert len(parts) == 4
        for p in parts:
            assert p, "empty block"
        for ch in parts[0]:
            assert ch in string.ascii_uppercase + string.digits

    def test_crypto_strong_distinct_values(self):
        ve = VariableEngine()
        seen = set()
        for _ in range(200):
            seen.add(ve.generate_invoice_number(used=seen))
        assert len(seen) == 200

    def test_collision_checking_avoids_used(self):
        ve = VariableEngine({"invoice_format": "{d2}"})  # tiny space: 100 values
        used = set()
        for _ in range(100):
            used.add(ve.generate_invoice_number(used=used))
        assert len(used) == 100
        with pytest.raises(ValueError):
            ve.generate_invoice_number(used=used)

    def test_custom_prefix_and_format(self):
        ve = VariableEngine({"invoice_prefix": "ACME-", "invoice_format": "{prefix}{r6}"})
        inv = ve.generate_invoice_number()
        assert inv.startswith("ACME-")
        body = inv[len("ACME-"):]
        assert len(body) == 6
        for ch in body:
            assert ch in string.ascii_lowercase + string.digits

    def test_date_token(self):
        ve = VariableEngine({"invoice_format": "{date}"})
        inv = ve.generate_invoice_number()
        assert len(inv) == 8 and inv.isdigit()

    def test_hash_token(self):
        ve = VariableEngine({"invoice_format": "{hash4}"})
        inv = ve.generate_invoice_number()
        # token_hex(4) -> 8 hex chars
---ENGINE---
    text: str
    unknown: list = field(default_factory=list)
    missing: list = field(default_factory=list)   # known but no data available
    used: list = field(default_factory=list)


class VariableEngine:
    def __init__(self, config: Optional[dict] = None, rng=None):
        self.config = config or {}
        self.rng = rng or secrets.SystemRandom()

    # ------------------------------------------------------------------ helpers
    def _cfg(self, key: str, default):
        return self.config.get(key, default)

    def generate_invoice_number(self, used: set = None) -> str:
        """Generate a unique invoice/reference number using configurable format tokens.

        Tokens: {prefix} {R#} uppercase {r#} lowercase {d#} digits {seq4} {date} {hash}
        Cryptographically strong randomness via SystemRandom.
        """
        used = used if used is not None else set()
        fmt = self._cfg("invoice_format", "{prefix}{R4}-{R5}-{R6}-{seq4}")
        prefix = self._cfg("invoice_prefix", "INV-")
        for _ in range(50):
            val = self._render_format(fmt, prefix)
            if val not in used:
                return val
        raise ValueError("Could not generate unique invoice number after 50 attempts")

    def _render_format(self, fmt: str, prefix: str) -> str:
        from string import ascii_letters, digits
        upper = string.ascii_uppercase + string.digits
        lower = string.ascii_lowercase + string.digits
        digits_only = string.digits

