"""
Company identity and country resolution (final master pass, §18).

The rule under test is the one §18 states explicitly: **a company's country must never be derived
from where it is listed.** The canonical structure the specification gives is real and common —
Company Country = China, Incorporation Country = Cayman Islands, Exchange Country = USA — and a
platform that collapses those into one field gets it wrong for every ADR.

Pure, dependency-free — genuinely executed. Dual-mode: pytest, or
`PYTHONPATH=. python3 tests/test_identity.py`.
"""
from __future__ import annotations

from app.engines.identity import (
    EXCHANGE_COUNTRY_BY_MIC,
    PROVENANCE_EXCHANGE_MIC,
    PROVENANCE_NOT_INGESTED,
    PROVENANCE_PROVIDER,
    PROVENANCE_UNKNOWN,
    exchange_country_for_mic,
    resolve_company_identity,
)


# --- the rule §18 is about ---


def test_a_chinese_company_listed_in_new_york_keeps_both_countries_separate():
    """The specification's own example. Before this module, `Company` had one country column and
    the Exchange row was created with the COMPANY's country, so NYSE would have been recorded as
    Chinese."""
    identity = resolve_company_identity(provider_country_iso2="CN", exchange_mic="NYSE")
    assert identity.company_country.iso2 == "CN"
    assert identity.company_country.provenance == PROVENANCE_PROVIDER
    assert identity.exchange_country.iso2 == "US"
    assert identity.exchange_country.provenance == PROVENANCE_EXCHANGE_MIC
    assert identity.is_cross_border_listing is True


def test_company_country_is_never_inferred_from_the_exchange():
    """The single most important assertion in this file. A provider that returns no country must
    leave the company's country UNKNOWN — not silently borrow the venue's."""
    identity = resolve_company_identity(provider_country_iso2=None, exchange_mic="NYSE")
    assert identity.company_country.iso2 is None
    assert identity.company_country.provenance == PROVENANCE_UNKNOWN
    assert "NOT defaulted to the exchange" in (identity.company_country.reason or "")
    # ...while the venue's own country is still known, because that is a fact about the venue.
    assert identity.exchange_country.iso2 == "US"


def test_a_domestic_listing_is_not_flagged_as_cross_border():
    identity = resolve_company_identity("US", "NASDAQ")
    assert identity.is_cross_border_listing is False


def test_cross_border_is_none_rather_than_false_when_either_side_is_unknown():
    """"We do not know" must not be reported as "they match"."""
    assert resolve_company_identity(None, "NYSE").is_cross_border_listing is None
    assert resolve_company_identity("CN", None).is_cross_border_listing is None
    assert resolve_company_identity("CN", "XXXX").is_cross_border_listing is None


# --- incorporation and headquarters are not ingested, and must say so ---


def test_incorporation_and_headquarters_are_declared_not_ingested_not_copied():
    """FMP and EODHD each return ONE country field. Mapping it to three different questions and
    presenting the answer three times would be fabrication."""
    identity = resolve_company_identity("CN", "NYSE")
    for fact in (identity.incorporation_country, identity.headquarters_country):
        assert fact.iso2 is None
        assert fact.provenance == PROVENANCE_NOT_INGESTED
        assert fact.reason
    # in particular, neither silently equals the provider's country
    assert identity.incorporation_country.iso2 != identity.company_country.iso2


# --- the exchange table itself ---


def test_exchange_country_is_resolved_from_an_explicit_table():
    assert exchange_country_for_mic("XNYS").iso2 == "US"
    assert exchange_country_for_mic("XLON").iso2 == "GB"
    assert exchange_country_for_mic("XTKS").iso2 == "JP"
    assert exchange_country_for_mic("XHKG").iso2 == "HK"


def test_exchange_code_matching_is_case_and_whitespace_insensitive():
    assert exchange_country_for_mic("  xnys  ").iso2 == "US"


def test_fmp_style_exchange_short_names_are_accepted_alongside_real_mics():
    """FMP returns `exchangeShortName` ("NASDAQ"), not an ISO 10383 MIC ("XNAS"). Both resolve, and
    the alias is an explicit table entry rather than a fuzzy match."""
    assert exchange_country_for_mic("NASDAQ").iso2 == exchange_country_for_mic("XNAS").iso2 == "US"
    assert exchange_country_for_mic("TSX").iso2 == exchange_country_for_mic("XTSE").iso2 == "CA"


def test_an_unknown_exchange_code_is_unknown_not_guessed():
    """No suffix parsing, no "probably US". An unrecognised venue must be added to the table
    deliberately, and the reason says so."""
    fact = exchange_country_for_mic("ZZZZ")
    assert fact.iso2 is None
    assert fact.provenance == PROVENANCE_UNKNOWN
    assert "EXCHANGE_COUNTRY_BY_MIC" in (fact.reason or "")


def test_a_missing_exchange_code_is_unknown():
    fact = exchange_country_for_mic(None)
    assert fact.iso2 is None and fact.provenance == PROVENANCE_UNKNOWN


def test_every_exchange_table_entry_is_a_two_letter_uppercase_iso_code():
    """A typo here would silently mislabel every company on that venue."""
    for mic, iso2 in EXCHANGE_COUNTRY_BY_MIC.items():
        assert mic == mic.upper(), mic
        assert len(iso2) == 2 and iso2.isupper() and iso2.isalpha(), (mic, iso2)


def test_the_exchange_table_covers_every_region_the_spec_names():
    """§19 lists the regions the universe must support. This asserts the venue table is not
    quietly US-only."""
    covered = set(EXCHANGE_COUNTRY_BY_MIC.values())
    for iso2 in ("US", "CA", "GB", "DE", "FR", "CN", "HK", "JP", "IN", "AU", "SG", "KR", "TW",
                 "BR", "MX", "ZA"):
        assert iso2 in covered, f"no exchange mapped to {iso2}"


# --- serialisation for the API ---


def test_as_dict_carries_provenance_for_every_field():
    payload = resolve_company_identity("CN", "NYSE").as_dict()
    assert set(payload) == {"company_country", "exchange_country", "incorporation_country",
                            "headquarters_country"}
    for name, entry in payload.items():
        assert set(entry) == {"iso2", "provenance", "reason"}, name
        assert entry["provenance"], name


ALL_TESTS = [v for k, v in sorted(globals().items()) if k.startswith("test_")]

if __name__ == "__main__":
    passed = failed = 0
    for t in ALL_TESTS:
        try:
            t()
            print(f"PASS  {t.__name__}")
            passed += 1
        except Exception as exc:  # noqa: BLE001
            print(f"FAIL  {t.__name__}: {exc}")
            failed += 1
    print(f"\n{passed}/{passed + failed} passed")
    raise SystemExit(1 if failed else 0)
