"""
Test Suite for Patent Valuation Tools

Tests all calculation tools and API tools in patent_valuation_system.py
"""

import asyncio
import logging
import sys
from pathlib import Path

# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent))

# Import all tools from patent_valuation_system
from patent_valuation_system import (
    # Calculation tools
    tool_tam_calculator,
    tool_sam_calculator,
    tool_som_calculator,
    tool_patent_strength_scorer,
    tool_trl_to_maturity_risk,
    tool_risk_premium_calculator,
    tool_attribution_comparable_license,
    tool_attribution_ssu,
    tool_attribution_feature_value,
    tool_commercialization_probability,
    tool_discount_rate_calculator,
    tool_dcf_calculator,
    tool_sensitivity_analyzer,
    # API/Data tools
    tool_uspto_patentsview_api,
    tool_epo_ops_api,
    tool_cpc_to_naics_mapper,
    tool_web_search,
    tool_sec_edgar_search,
    tool_damodaran_lookup,
)

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)


def print_section(title: str):
    """Print formatted section header"""
    print("\n" + "=" * 80)
    print(f"  {title}")
    print("=" * 80)


def print_result(test_name: str, result: dict):
    """Print test result in formatted way"""
    print(f"\n✅ {test_name}")
    print("-" * 80)
    for key, value in result.items():
        if isinstance(value, dict):
            print(f"  {key}:")
            for k, v in value.items():
                print(f"    {k}: {v}")
        elif isinstance(value, list):
            print(f"  {key}: {value[:3]}..." if len(value) > 3 else f"  {key}: {value}")
        else:
            print(f"  {key}: {value}")


# ============================================================================
# TEST CALCULATION TOOLS
# ============================================================================

def test_calculation_tools():
    """Test all pure Python calculation tools"""
    print_section("TESTING CALCULATION TOOLS")

    # Test TAM Calculator
    print("\n1. TAM Calculator")
    result = tool_tam_calculator(
        total_customers=1_000_000,
        arpu=100.0,
        purchase_frequency=1.0
    )
    print_result("TAM Calculator", result)
    assert result["tam"] == 100_000_000, "TAM calculation incorrect"

    # Test SAM Calculator
    print("\n2. SAM Calculator")
    result = tool_sam_calculator(
        tam=100_000_000,
        geographic_filter=0.5,
        distribution_filter=0.8,
        product_fit_filter=0.6
    )
    print_result("SAM Calculator", result)
    assert result["sam"] == 24_000_000, "SAM calculation incorrect"

    # Test SOM Calculator
    print("\n3. SOM Calculator")
    result = tool_som_calculator(
        sam=24_000_000,
        market_share=0.05,
        adoption_rate=0.3
    )
    print_result("SOM Calculator", result)
    assert result["som"] == 360_000, "SOM calculation incorrect"

    # Test Patent Strength Scorer
    print("\n4. Patent Strength Scorer")
    result = tool_patent_strength_scorer(
        forward_citations=50,
        patent_age_years=8,
        family_size=12,
        independent_claims=3,
        total_claims=20,
        maintenance_fees_paid=True,
        litigation_history="none"
    )
    print_result("Patent Strength Scorer", result)
    assert "total_score" in result, "Missing total_score"
    assert "citation" in result, "Missing academic citation"

    # Test TRL to Maturity Risk
    print("\n5. TRL to Maturity Risk")
    risk = tool_trl_to_maturity_risk(trl_level=7)
    print(f"  TRL 7 → Maturity Risk: {risk:.1%}")
    assert risk == 0.04, "TRL risk mapping incorrect"

    # Test Risk Premium Calculator
    print("\n6. Risk Premium Calculator")
    result = tool_risk_premium_calculator(
        maturity_risk=0.04,
        dependency_risk=0.03,
        litigation_risk=0.01
    )
    print_result("Risk Premium Calculator", result)
    assert result["total_risk_premium"] == 0.08, "Risk premium calculation incorrect"

    # Test Attribution - Comparable License
    print("\n7. Attribution - Comparable License")
    ip_contribution = tool_attribution_comparable_license(
        royalty_rate=0.03,
        profit_margin=0.10
    )
    print(f"  IP Contribution: {ip_contribution:.1%}")
    assert ip_contribution == 0.30, "Attribution calculation incorrect"

    # Test Attribution - SSU
    print("\n8. Attribution - SSU (Smallest Salable Unit)")
    ip_contribution = tool_attribution_ssu(
        component_value=50,
        total_product_value=500,
        patent_share_in_component=0.6
    )
    print(f"  IP Contribution: {ip_contribution:.1%}")
    assert ip_contribution == 0.06, "SSU calculation incorrect"

    # Test Attribution - Feature Value
    print("\n9. Attribution - Feature Value")
    ip_contribution = tool_attribution_feature_value(
        patented_feature_values=[20, 15, 10],
        all_feature_values=[20, 15, 10, 8, 7, 5]
    )
    print(f"  IP Contribution: {ip_contribution:.1%}")
    assert abs(ip_contribution - 0.692) < 0.01, "Feature value calculation incorrect"

    # Test Commercialization Probability
    print("\n10. Commercialization Probability (TRL-CRL Matrix)")
    result = tool_commercialization_probability(trl=8, crl=7)
    print_result("Commercialization Probability", result)
    assert "probability" in result, "Missing probability"
    assert "citation" in result, "Missing NASA citation"

    # Test Discount Rate Calculator
    print("\n11. Discount Rate Calculator")
    result = tool_discount_rate_calculator(
        industry_wacc=0.095,
        risk_premium=0.06
    )
    print_result("Discount Rate Calculator", result)
    assert result["discount_rate"] == 0.155, "Discount rate calculation incorrect"

    # Test DCF Calculator
    print("\n12. DCF Calculator")
    cash_flows = [100000, 110000, 121000, 133100, 146410]
    result = tool_dcf_calculator(
        cash_flows=cash_flows,
        discount_rate=0.15,
        periods=5
    )
    print_result("DCF Calculator", result)
    assert "npv" in result, "Missing NPV"
    assert len(result["cash_flows_pv"]) == 5, "Incorrect cash flow count"

    # Test Sensitivity Analyzer
    print("\n13. Sensitivity Analyzer")

    def mock_valuation_calc(**params):
        return params.get("base_revenue", 100000) * params.get("multiplier", 1.0)

    result = tool_sensitivity_analyzer(
        base_valuation=100000,
        base_params={"base_revenue": 100000, "multiplier": 1.0},
        calculate_fn=mock_valuation_calc
    )
    print_result("Sensitivity Analyzer", result)
    assert "sensitivity" in result, "Missing sensitivity analysis"

    print("\n" + "=" * 80)
    print("✅ ALL CALCULATION TOOLS PASSED")
    print("=" * 80)


# ============================================================================
# TEST API/DATA TOOLS
# ============================================================================

def test_api_tools():
    """Test all API and data access tools"""
    print_section("TESTING API/DATA TOOLS")

    # Test USPTO PatentsView (via patent_client or mock)
    print("\n1. USPTO PatentsView API (patent_client)")
    result = tool_uspto_patentsview_api("10123456")
    print_result("USPTO PatentsView", result)
    assert "patent_number" in result, "Missing patent_number"
    assert "title" in result, "Missing title"
    assert "source" in result, "Missing source"

    # Test EPO OPS API (will be mock unless credentials set)
    print("\n2. EPO OPS API")
    result = tool_epo_ops_api("US10123456B2")
    print_result("EPO OPS API", result)
    assert "family_size" in result, "Missing family_size"

    # Test CPC to NAICS Mapper (mock unless concordance loaded)
    print("\n3. CPC to NAICS Mapper")
    result = tool_cpc_to_naics_mapper(["H02J50/10", "H01M10/44"])
    print_result("CPC-NAICS Mapper", result)
    assert "primary_industry" in result, "Missing primary_industry"
    assert "source" in result, "Missing source"

    # Test Web Search (stub)
    print("\n4. Web Search")
    result = tool_web_search("quantum computing applications")
    print_result("Web Search", result)
    assert "results" in result, "Missing results"

    # Test SEC EDGAR (REAL API - requires CIK)
    print("\n5. SEC EDGAR API (Testing with Apple Inc.)")
    result = tool_sec_edgar_search(
        company_name="Apple Inc.",
        cik="320193"  # Apple's CIK
    )
    print_result("SEC EDGAR", result)
    assert "company_name" in result, "Missing company_name"
    if result.get("found"):
        print("  ✅ Successfully fetched real SEC EDGAR data!")
        assert "filings" in result, "Missing filings"

    # Test Damodaran Lookup (REAL DATA - downloads if needed)
    print("\n6. Damodaran Industry Data (Testing with 'Computer')")
    result = tool_damodaran_lookup("Computer")
    print_result("Damodaran Lookup", result)
    assert "industry" in result, "Missing industry"
    assert "wacc" in result, "Missing wacc"
    assert "profit_margin" in result, "Missing profit_margin"
    if "error" not in result:
        print("  ✅ Successfully fetched real Damodaran data!")
        assert result["wacc"] > 0, "WACC should be positive"

    print("\n" + "=" * 80)
    print("✅ ALL API/DATA TOOLS TESTED")
    print("=" * 80)


# ============================================================================
# TEST EDGE CASES
# ============================================================================

def test_edge_cases():
    """Test edge cases and error handling"""
    print_section("TESTING EDGE CASES & ERROR HANDLING")

    # Test division by zero protection
    print("\n1. Error Handling - Zero Profit Margin")
    try:
        tool_attribution_comparable_license(0.03, 0.0)
        assert False, "Should have raised ValueError"
    except ValueError as e:
        print(f"  ✅ Correctly raised error: {e}")

    # Test empty feature list
    print("\n2. Error Handling - Empty Feature List")
    try:
        tool_attribution_feature_value([], [1, 2, 3])
        assert False, "Should have raised ValueError"
    except ValueError as e:
        print(f"  ✅ Correctly raised error: {e}")

    # Test out of range TRL
    print("\n3. Edge Case - Invalid TRL (defaults to medium risk)")
    risk = tool_trl_to_maturity_risk(99)
    print(f"  TRL 99 → Risk: {risk:.1%} (default)")
    assert risk == 0.06, "Should default to medium risk"

    # Test empty CPC codes
    print("\n4. Edge Case - Empty CPC Codes")
    result = tool_cpc_to_naics_mapper([])
    print(f"  Result: {result.get('error', 'No error')}")
    assert "error" in result or result.get("primary_industry") is None

    # Test SEC EDGAR without CIK
    print("\n5. Error Handling - SEC EDGAR without CIK")
    result = tool_sec_edgar_search("Unknown Company")
    print(f"  Result: {result.get('error', 'No error')}")
    assert result["found"] == False, "Should not find company without CIK"

    print("\n" + "=" * 80)
    print("✅ ALL EDGE CASES HANDLED CORRECTLY")
    print("=" * 80)


# ============================================================================
# INTEGRATION TEST
# ============================================================================

def test_integration():
    """Test tools working together in realistic scenario"""
    print_section("INTEGRATION TEST - Realistic Valuation Scenario")

    print("\nScenario: Valuing a wireless charging patent")
    print("-" * 80)

    # Step 1: Get patent data
    print("\n1. Retrieving patent data...")
    patent_data = tool_uspto_patentsview_api("10123456")
    print(f"  Patent: {patent_data.get('title', 'Unknown')}")
    print(f"  Age: {patent_data.get('patent_age_years', 0)} years")
    print(f"  Remaining life: {patent_data.get('remaining_life_years', 0)} years")

    # Step 2: Map to industry
    print("\n2. Mapping to industry...")
    cpc_codes = patent_data.get("cpc_codes", ["H02J50/10"])
    industry_data = tool_cpc_to_naics_mapper(cpc_codes)
    industry_name = industry_data.get("primary_industry", "Electrical Equipment")
    print(f"  Industry: {industry_name}")

    # Step 3: Get financial data
    print("\n3. Getting industry financial data...")
    financial_data = tool_damodaran_lookup("Electrical")
    wacc = financial_data.get("wacc", 0.10)
    profit_margin = financial_data.get("profit_margin", 0.10)
    print(f"  WACC: {wacc:.1%}")
    print(f"  Profit Margin: {profit_margin:.1%}")

    # Step 4: Calculate market size (mock)
    print("\n4. Calculating market size...")
    tam = tool_tam_calculator(5_000_000, 150, 1.0)
    sam = tool_sam_calculator(tam["tam"], 0.4, 0.7, 0.5)
    som = tool_som_calculator(sam["sam"], 0.03, 0.4)
    print(f"  TAM: ${tam['tam']:,.0f}")
    print(f"  SAM: ${sam['sam']:,.0f}")
    print(f"  SOM: ${som['som']:,.0f}")

    # Step 5: Calculate patent strength and risk
    print("\n5. Assessing patent strength...")
    strength = tool_patent_strength_scorer(
        forward_citations=patent_data.get("forward_citations", 47),
        patent_age_years=patent_data.get("patent_age_years", 7),
        family_size=12,
        independent_claims=patent_data.get("independent_claims", 3),
        total_claims=patent_data.get("total_claims", 20),
        maintenance_fees_paid=True,
        litigation_history="none"
    )
    print(f"  Strength Score: {strength['total_score']:.1f}/100")

    trl = 8  # Assume mature technology
    maturity_risk = tool_trl_to_maturity_risk(trl)
    risk_premium_data = tool_risk_premium_calculator(maturity_risk, 0.02, 0.01)
    total_risk = risk_premium_data["total_risk_premium"]
    print(f"  TRL: {trl}")
    print(f"  Risk Premium: {total_risk:.1%}")

    # Step 6: Calculate discount rate
    print("\n6. Calculating discount rate...")
    discount_data = tool_discount_rate_calculator(wacc, total_risk)
    discount_rate = discount_data["discount_rate"]
    print(f"  Discount Rate: {discount_rate:.1%}")

    # Step 7: Calculate attribution
    print("\n7. Calculating IP attribution...")
    ip_contribution = tool_attribution_comparable_license(0.04, profit_margin)
    print(f"  IP Contribution Factor: {ip_contribution:.1%}")

    # Step 8: Commercialization probability
    print("\n8. Assessing commercialization...")
    comm_data = tool_commercialization_probability(trl=8, crl=7)
    comm_prob = comm_data["probability"]
    print(f"  Commercialization Probability: {comm_prob:.1%}")

    # Step 9: Calculate cash flows
    print("\n9. Calculating DCF...")
    base_revenue = som["som"]
    growth_rate = 0.05
    remaining_life = patent_data.get("remaining_life_years", 13)

    cash_flows = []
    for year in range(1, min(remaining_life + 1, 11)):  # Max 10 years
        revenue = base_revenue * ((1 + growth_rate) ** (year - 1))
        cf = revenue * profit_margin * ip_contribution * comm_prob
        cash_flows.append(cf)

    dcf_result = tool_dcf_calculator(cash_flows, discount_rate, len(cash_flows))
    valuation = dcf_result["npv"]

    print(f"  Annual Cash Flows (sample):")
    for i, cf_data in enumerate(dcf_result["cash_flows_pv"][:3], 1):
        print(f"    Year {i}: CF=${cf_data['cf']:,.0f} → PV=${cf_data['pv']:,.0f}")
    print(f"  ...")
    print(f"\n  💰 PATENT VALUATION: ${valuation:,.0f}")

    print("\n" + "=" * 80)
    print("✅ INTEGRATION TEST COMPLETE")
    print("=" * 80)


# ============================================================================
# MAIN TEST RUNNER
# ============================================================================

def run_all_tests():
    """Run all test suites"""
    print("\n" + "=" * 80)
    print("  PATENT VALUATION TOOLS - COMPREHENSIVE TEST SUITE")
    print("=" * 80)

    try:
        # Test calculation tools (always work)
        test_calculation_tools()

        # Test API tools (may require network/dependencies)
        test_api_tools()

        # Test edge cases
        test_edge_cases()

        # Integration test
        test_integration()

        # Final summary
        print("\n" + "=" * 80)
        print("  🎉 ALL TESTS PASSED SUCCESSFULLY! 🎉")
        print("=" * 80)
        print("\nSummary:")
        print("  ✅ 13 Calculation tools tested")
        print("  ✅ 6 API/Data tools tested")
        print("  ✅ 5 Edge cases verified")
        print("  ✅ 1 Integration test completed")
        print("\nTotal: 25+ test scenarios executed")
        print("=" * 80 + "\n")

        return 0

    except AssertionError as e:
        print(f"\n❌ TEST FAILED: {e}")
        return 1
    except Exception as e:
        print(f"\n❌ UNEXPECTED ERROR: {e}")
        import traceback
        traceback.print_exc()
        return 1


if __name__ == "__main__":
    exit_code = run_all_tests()
    sys.exit(exit_code)
