"""Tests for GSTIN verification + duplicate-prevention in Parties."""
import os
import time
import pytest
import requests

BASE = os.environ.get("REACT_APP_BACKEND_URL", "https://offline-billing-pro-2.preview.emergentagent.com").rstrip("/")
ADMIN_EMAIL = os.environ.get("TEST_ADMIN_EMAIL", "regalmarketing2024@gmail.com")
ADMIN_PASSWORD = os.environ.get("TEST_ADMIN_PASSWORD", "Rvasa@#9955")


def _s():
    s = requests.Session()
    s.headers.update({"Content-Type": "application/json"})
    return s


@pytest.fixture(scope="module")
def admin():
    s = _s()
    r = s.post(f"{BASE}/api/auth/login", json={"email": ADMIN_EMAIL, "password": ADMIN_PASSWORD}, timeout=20)
    assert r.status_code == 200, r.text
    body = r.json()
    if body.get("requires_wa_otp"):
        pytest.skip("Admin has wa_otp_enabled; toggle off before running this module")
    return s


@pytest.fixture(scope="module")
def company_id(admin):
    """Pick the first existing company so tests don't pollute fixtures."""
    r = admin.get(f"{BASE}/api/companies", timeout=20)
    assert r.status_code == 200, r.text
    cos = r.json()
    if not cos:
        pytest.skip("No companies — fixture cannot proceed")
    return cos[0]["id"]


class TestVerifyEndpoint:
    def test_provider_status_requires_auth(self):
        r = _s().get(f"{BASE}/api/gst/provider-status", timeout=20)
        assert r.status_code == 401

    def test_provider_status_returns_provider(self, admin):
        r = admin.get(f"{BASE}/api/gst/provider-status", timeout=20)
        assert r.status_code == 200
        d = r.json()
        assert "provider" in d
        assert "is_live" in d
        assert "cache_ttl_hours" in d

    def test_verify_known_stub_gstin_returns_full_details(self, admin):
        r = admin.post(f"{BASE}/api/gst/verify", json={"gstin": "30ARLPR3709H1ZT"}, timeout=20)
        assert r.status_code == 200, r.text
        d = r.json()
        assert d["valid"] is True
        assert d["found"] is True
        assert d["legal_name"]
        assert d["state"]
        assert d["pan"] == "ARLPR3709H"
        assert "looked_up_at" in d

    def test_verify_invalid_checksum_short_circuits(self, admin):
        r = admin.post(f"{BASE}/api/gst/verify", json={"gstin": "30ARLPR3709H1ZA"}, timeout=20)
        assert r.status_code == 200
        d = r.json()
        assert d["valid"] is False
        assert "checksum" in d["reason"].lower()
        assert d["found"] is False

    def test_verify_caches_result(self, admin):
        """Second call within TTL window should be served from cache."""
        # First call may or may not be cached (depends on prior tests)
        admin.post(f"{BASE}/api/gst/verify", json={"gstin": "27AAAAA0000A1Z2"}, timeout=20)
        # Second call → should now hit cache
        r = admin.post(f"{BASE}/api/gst/verify", json={"gstin": "27AAAAA0000A1Z2"}, timeout=20)
        d = r.json()
        assert d.get("from_cache") is True
        assert d["legal_name"] == "DEMO ENTERPRISES PVT LTD"

    def test_verify_force_refresh_bypasses_cache(self, admin):
        # Prime cache
        admin.post(f"{BASE}/api/gst/verify", json={"gstin": "30ARLPR3709H1ZT"}, timeout=20)
        # Force refresh
        r = admin.post(f"{BASE}/api/gst/verify", json={"gstin": "30ARLPR3709H1ZT", "force_refresh": True}, timeout=20)
        d = r.json()
        # The very fresh fetch shouldn't be marked from_cache
        assert d.get("from_cache") in (False, None)

    def test_admin_clear_cache(self, admin):
        admin.post(f"{BASE}/api/gst/verify", json={"gstin": "27AAAAA0000A1Z2"}, timeout=20)
        r = admin.delete(f"{BASE}/api/gst/cache/27AAAAA0000A1Z2", timeout=20)
        assert r.status_code == 200
        # After clearing, next call should NOT come from cache
        r2 = admin.post(f"{BASE}/api/gst/verify", json={"gstin": "27AAAAA0000A1Z2"}, timeout=20)
        d = r2.json()
        assert d.get("from_cache") in (False, None)


class TestDuplicatePartyDetection:
    def test_duplicate_party_flag_in_response(self, admin, company_id):
        """If a party with this GSTIN already exists in the company, response
        should include `duplicate_party`."""
        # Create a party with a known GSTIN
        unique_gstin = "27AAAAA0000A1Z2"
        ts = int(time.time())
        # Clean up any stale matching parties first
        # (we can't list-and-delete via API for tests, so use a unique-ish name)
        create = admin.post(
            f"{BASE}/api/parties?company_id={company_id}",
            json={"name": f"GST-Verify Dup Test {ts}", "type": "customer", "gstin": unique_gstin,
                  "phone": "9999999999"},
            timeout=20,
        )
        if create.status_code == 409:
            # Already exists — fine for this assertion
            pass
        else:
            assert create.status_code == 200, create.text
        # Now verify the same GSTIN with company_id → should detect duplicate
        r = admin.post(f"{BASE}/api/gst/verify",
                       json={"gstin": unique_gstin, "company_id": company_id}, timeout=20)
        d = r.json()
        assert d.get("duplicate_party"), f"Expected duplicate_party flag, got {d}"

    def test_duplicate_gstin_create_rejected(self, admin, company_id):
        """Trying to CREATE a party with a GSTIN already used in the company → 409."""
        unique_gstin = "30ARLPR3709H1ZT"
        ts = int(time.time())
        admin.post(
            f"{BASE}/api/parties?company_id={company_id}",
            json={"name": f"Dup Guard A {ts}", "type": "customer", "gstin": unique_gstin},
            timeout=20,
        )
        r = admin.post(
            f"{BASE}/api/parties?company_id={company_id}",
            json={"name": f"Dup Guard B {ts}", "type": "vendor", "gstin": unique_gstin},
            timeout=20,
        )
        assert r.status_code == 409, r.text
        assert "GSTIN" in r.json().get("detail", "") or "gstin" in r.json().get("detail", "").lower()

    def test_empty_gstin_does_not_trigger_duplicate(self, admin, company_id):
        """Parties without GSTIN can be created freely — duplicate guard skips empties."""
        ts = int(time.time())
        r1 = admin.post(
            f"{BASE}/api/parties?company_id={company_id}",
            json={"name": f"NoGST A {ts}", "type": "customer", "gstin": ""},
            timeout=20,
        )
        r2 = admin.post(
            f"{BASE}/api/parties?company_id={company_id}",
            json={"name": f"NoGST B {ts}", "type": "customer", "gstin": ""},
            timeout=20,
        )
        assert r1.status_code == 200 and r2.status_code == 200
