"""
test_pdf_generator.py — Tests for negoT8 Deal Agreement PDF generation

Run from the project root:
    cd /path/to/negot8
    python test/test_pdf_generator.py

What this tests:
  1. Freelance deal PDF — rich details (budget, scope, timeline, payment)
  2. Marketplace (buy/sell) PDF — item, price, delivery
  3. Minimal data  — all optional fields absent; should still produce a valid PDF
  4. Blockchain proof attached — real-looking proof dict
  5. Mock blockchain proof   — mock=True path
  6. File is actually written to /tmp and is non-empty
  7. Temp-file cleanup helper works
"""

import asyncio
import os
import sys

# ── Make sure backend/ is on the path ────────────────────────────────────────
BACKEND = os.path.join(os.path.dirname(__file__), "..", "backend")
sys.path.insert(0, os.path.abspath(BACKEND))

from tools.pdf_generator import generate_deal_pdf

# ─────────────────────────────────────────────────────────────────────────────
# Shared fixtures
# ─────────────────────────────────────────────────────────────────────────────

USER_A = {"id": 111111111, "name": "Alice Sharma",   "username": "alice_s"}
USER_B = {"id": 222222222, "name": "Bob Chatterjee", "username": "bobchat"}

REAL_PROOF = {
    "success":        True,
    "mock":           False,
    "tx_hash":        "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "block_number":   87654321,
    "agreement_hash": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
    "explorer_url":   "https://amoy.polygonscan.com/tx/0xabcdef1234567890",
    "gas_used":       42000,
}

MOCK_PROOF = {
    "success":        True,
    "mock":           True,
    "tx_hash":        "0xMOCKTX1234567890",
    "block_number":   0,
    "agreement_hash": "0xMOCKHASH1234567890",
    "explorer_url":   "",
    "gas_used":       0,
}

# ─────────────────────────────────────────────────────────────────────────────
# Test helpers
# ─────────────────────────────────────────────────────────────────────────────

def _check_pdf(path: str, label: str):
    """Assert the file exists, is non-empty, and starts with the PDF magic bytes."""
    assert os.path.exists(path),    f"[{label}] PDF file not found at {path}"
    size = os.path.getsize(path)
    assert size > 500,              f"[{label}] PDF suspiciously small: {size} bytes"
    with open(path, "rb") as f:
        magic = f.read(4)
    assert magic == b"%PDF",        f"[{label}] File does not start with PDF magic bytes: {magic}"
    print(f"  ✅  [{label}] PDF OK — {size:,} bytes → {path}")


def _cleanup(path: str):
    try:
        os.remove(path)
    except OSError:
        pass


# ─────────────────────────────────────────────────────────────────────────────
# Individual tests
# ─────────────────────────────────────────────────────────────────────────────

async def test_freelance_full():
    """Freelance deal with full details + real blockchain proof."""
    final_proposal = {
        "summary": "Alice will build the dashboard in 3 weeks for Rs. 45,000 with 50% upfront.",
        "details": {
            "budget":           "45000",
            "timeline":         "3 weeks",
            "scope":            ["Admin dashboard", "REST API integration", "Mobile responsive UI"],
            "payment_schedule": "50% upfront (Rs. 22,500) + 50% on delivery",
            "upfront":          "22500",
            "ip_ownership":     "Full transfer to client on final payment",
        },
    }
    preferences_a = {
        "goal": "Build a dashboard",
        "raw_details": {
            "role": "freelancer", "skill": "React + FastAPI",
            "rate": "1500", "hours": "30", "upfront_minimum": "50",
        },
    }
    preferences_b = {
        "goal": "Hire a developer",
        "raw_details": {
            "role": "client", "budget": "45000",
            "required_features": ["Admin dashboard", "API", "Mobile UI"],
        },
    }

    path = await generate_deal_pdf(
        negotiation_id   = "freelance_test_001",
        feature_type     = "freelance",
        final_proposal   = final_proposal,
        user_a           = USER_A,
        user_b           = USER_B,
        rounds_taken     = 4,
        sat_a            = 85.0,
        sat_b            = 78.0,
        preferences_a    = preferences_a,
        preferences_b    = preferences_b,
        blockchain_proof = REAL_PROOF,
    )
    _check_pdf(path, "freelance_full")
    _cleanup(path)


async def test_marketplace_full():
    """Buy/sell deal with full details + mock blockchain proof."""
    final_proposal = {
        "summary": "iPhone 14 sold for Rs. 52,000. Pickup at Andheri station on Saturday.",
        "details": {
            "agreed_price": "52000",
            "delivery":     "Pickup — Andheri West Metro station, Saturday 4 PM",
            "condition":    "Used — 6 months old, no scratches",
            "market_price": "55000",
        },
    }
    preferences_a = {
        "goal": "Sell iPhone 14",
        "raw_details": {
            "role": "seller", "item": "iPhone 14 128GB Black",
            "asking_price": "55000", "minimum_price": "50000",
        },
    }
    preferences_b = {
        "goal": "Buy iPhone 14",
        "raw_details": {
            "role": "buyer", "item": "iPhone 14",
            "max_budget": "54000", "offer_price": "49000",
        },
    }

    path = await generate_deal_pdf(
        negotiation_id   = "marketplace_test_001",
        feature_type     = "marketplace",
        final_proposal   = final_proposal,
        user_a           = USER_A,
        user_b           = USER_B,
        rounds_taken     = 3,
        sat_a            = 72.0,
        sat_b            = 88.0,
        preferences_a    = preferences_a,
        preferences_b    = preferences_b,
        blockchain_proof = MOCK_PROOF,
    )
    _check_pdf(path, "marketplace_full")
    _cleanup(path)


async def test_minimal_data():
    """Both feature_type is unknown and all optional fields are empty — should not crash."""
    path = await generate_deal_pdf(
        negotiation_id   = "minimal_test_001",
        feature_type     = "generic",
        final_proposal   = {"summary": "Parties agreed to share expenses equally."},
        user_a           = {"id": 1, "name": "", "username": "userA"},
        user_b           = {"id": 2, "name": "", "username": "userB"},
        rounds_taken     = 1,
        sat_a            = 60.0,
        sat_b            = 60.0,
        blockchain_proof = None,
    )
    _check_pdf(path, "minimal_data")
    _cleanup(path)


async def test_no_blockchain_proof():
    """Freelance deal where blockchain proof hasn't been registered yet."""
    final_proposal = {
        "summary": "React Native app, Rs. 80,000, 6 weeks.",
        "details": {
            "budget":   "80000",
            "timeline": "6 weeks",
            "scope":    ["React Native app", "Backend API"],
        },
    }
    path = await generate_deal_pdf(
        negotiation_id   = "noproof_test_001",
        feature_type     = "freelance",
        final_proposal   = final_proposal,
        user_a           = USER_A,
        user_b           = USER_B,
        rounds_taken     = 5,
        sat_a            = 90.0,
        sat_b            = 70.0,
        blockchain_proof = None,
    )
    _check_pdf(path, "no_blockchain_proof")
    _cleanup(path)


async def test_unicode_safe():
    """
    Ensure the PDF builder doesn't crash on characters outside Latin-1
    (Rs. symbol ₹, em-dashes, etc.).
    """
    final_proposal = {
        "summary": "₹45,000 deal — React dashboard — agreed ✓",
        "details": {
            "budget":   "₹45,000",
            "timeline": "3 weeks – confirmed",
            "scope":    ["Dashboard • Admin panel", "API • REST"],
        },
    }
    path = await generate_deal_pdf(
        negotiation_id   = "unicode_test_001",
        feature_type     = "freelance",
        final_proposal   = final_proposal,
        user_a           = {"id": 1, "name": "Anirbán Bāsak", "username": "anirban"},
        user_b           = {"id": 2, "name": "Rāhul Gupta",   "username": "rahul"},
        rounds_taken     = 2,
        sat_a            = 88.0,
        sat_b            = 82.0,
        blockchain_proof = MOCK_PROOF,
    )
    _check_pdf(path, "unicode_safe")
    _cleanup(path)


# ─────────────────────────────────────────────────────────────────────────────
# Runner
# ─────────────────────────────────────────────────────────────────────────────

TESTS = [
    ("Freelance full details + real blockchain proof", test_freelance_full),
    ("Marketplace (buy/sell) + mock proof",            test_marketplace_full),
    ("Minimal / sparse data — no crash",               test_minimal_data),
    ("No blockchain proof yet",                        test_no_blockchain_proof),
    ("Unicode / special chars — Latin-1 safety",       test_unicode_safe),
]


async def main():
    print("\n🧪  negoT8 — PDF Generator Tests")
    print("=" * 52)

    passed = 0
    failed = 0

    for name, fn in TESTS:
        print(f"\n▶  {name}")
        try:
            await fn()
            passed += 1
        except Exception as exc:
            import traceback
            print(f"  ❌  FAILED: {exc}")
            traceback.print_exc()
            failed += 1

    print("\n" + "=" * 52)
    print(f"Results:  {passed} passed  |  {failed} failed  |  {len(TESTS)} total")

    if failed == 0:
        print("✅  All PDF tests passed!\n")
    else:
        print("❌  Some tests failed — see output above.\n")
        sys.exit(1)


if __name__ == "__main__":
    asyncio.run(main())
