#!/usr/bin/env python3
"""
Comprehensive Policy Service API Test Suite
Tests all endpoints at https://policy-api-dev3.heyarchie.com
"""

import requests
import json
from datetime import datetime, timedelta
from typing import Dict, Any, Optional
import sys

BASE_URL = "https://policy-api-dev3.heyarchie.com"

# Test results tracking
test_results = []
created_policy_id = None


class TestResult:
    def __init__(self, test_name, endpoint, method, status_code, expected_status,
                 payload=None, response_body=None, passed=False, notes=""):
        self.test_name = test_name
        self.endpoint = endpoint
        self.method = method
        self.status_code = status_code
        self.expected_status = expected_status
        self.payload = payload
        self.response_body = response_body
        self.passed = passed
        self.notes = notes


def print_section(title):
    print("\n" + "="*80)
    print(title)
    print("="*80 + "\n")


def test_endpoint(test_name, method, endpoint, expected_status, payload=None, notes=""):
    """Execute API test and record result"""
    global created_policy_id

    url = f"{BASE_URL}{endpoint}"
    headers = {"Content-Type": "application/json"}

    print(f"Testing: {test_name}")
    print(f"  {method} {endpoint}")

    try:
        if method == "GET":
            response = requests.get(url, headers=headers)
        elif method == "POST":
            response = requests.post(url, headers=headers, json=payload)
        elif method == "PATCH":
            response = requests.patch(url, headers=headers, json=payload)
        elif method == "DELETE":
            response = requests.delete(url, headers=headers)
        else:
            raise ValueError(f"Unsupported HTTP method: {method}")

        status_code = response.status_code
        try:
            response_body = response.json()
        except:
            response_body = response.text

        passed = (status_code == expected_status)

        # Extract policy ID from successful creation
        if passed and method == "POST" and endpoint == "/v1/policies" and isinstance(response_body, dict):
            created_policy_id = response_body.get("id")

        result = TestResult(
            test_name=test_name,
            endpoint=endpoint,
            method=method,
            status_code=status_code,
            expected_status=expected_status,
            payload=payload,
            response_body=response_body,
            passed=passed,
            notes=notes
        )

        test_results.append(result)

        status_symbol = "✓" if passed else "✗"
        status_color = "\033[92m" if passed else "\033[91m"
        reset_color = "\033[0m"

        print(f"  {status_color}{status_symbol} Status: {status_code} (Expected: {expected_status}){reset_color}")

        if not passed:
            print(f"  Response: {json.dumps(response_body, indent=2)[:300]}")

        if notes:
            print(f"  Notes: {notes}")

        print()

        return result

    except Exception as e:
        print(f"  \033[91m✗ ERROR: {str(e)}\033[0m\n")
        result = TestResult(
            test_name=test_name,
            endpoint=endpoint,
            method=method,
            status_code=0,
            expected_status=expected_status,
            payload=payload,
            response_body=str(e),
            passed=False,
            notes=f"Exception: {str(e)}"
        )
        test_results.append(result)
        return result


def main():
    print_section("POLICY SERVICE API COMPREHENSIVE TEST REPORT")
    print(f"Base URL: {BASE_URL}")
    print(f"Test Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"Auth: Using auth stub (no authentication headers required)")

    # Test 0: Health Check
    print_section("TEST 0: Health Check")
    test_endpoint(
        "Health Check",
        "GET",
        "/health",
        200,
        notes="Verify service is running"
    )

    # Test 1: List Policies (Empty or with data)
    print_section("TEST 1: List Policies")
    test_endpoint(
        "List all policies",
        "GET",
        "/v1/policies",
        200,
        notes="May return 500 if database not initialized"
    )

    # Test 2: List with Pagination
    test_endpoint(
        "List policies with pagination",
        "GET",
        "/v1/policies?page=1&limit=10",
        200,
        notes="Test pagination parameters"
    )

    # Test 3: List with Filters
    test_endpoint(
        "List policies with filters",
        "GET",
        "/v1/policies?product_type=home&status=active",
        200,
        notes="Test filtering by product_type and status"
    )

    # Test 4: Create Policy - Valid Data
    print_section("TEST 4: Create Policy - Valid Data")

    effective_date = datetime.now().isoformat() + "Z"
    expiration_date = (datetime.now() + timedelta(days=365)).isoformat() + "Z"

    valid_policy = {
        "customer_id": "cus_01HQZK9X1Z2Y3W4V5U6T7S8R9Q",
        "product_type": "home",
        "status": "pending",
        "effective_date": effective_date,
        "expiration_date": expiration_date,
        "premium_amount": "1200.00",
        "currency": "USD",
        "billing_frequency": "monthly",
        "coverage_details": {
            "dwelling_coverage": 250000,
            "personal_property": 100000,
            "liability": 300000,
            "deductible": 1000
        },
        "underwriting_data": {
            "property_address": "123 Main St, Springfield, IL 62701",
            "construction_year": 1995,
            "square_footage": 2000,
            "property_type": "single_family"
        },
        "tags": ["test", "api-validation"],
        "metadata": {
            "source": "api_test",
            "test_run": datetime.now().isoformat()
        }
    }

    result = test_endpoint(
        "Create policy with all required fields",
        "POST",
        "/v1/policies",
        201,
        payload=valid_policy,
        notes="Should return 201 with policy ID. May fail with 500 if DB not set up."
    )

    # Test 5: Validation Errors
    print_section("TEST 5: Validation Errors")

    # Missing customer_id
    missing_customer = valid_policy.copy()
    del missing_customer["customer_id"]
    test_endpoint(
        "Missing required field (customer_id)",
        "POST",
        "/v1/policies",
        422,
        payload=missing_customer,
        notes="Should return validation error"
    )

    # Missing product_type
    missing_product = valid_policy.copy()
    del missing_product["product_type"]
    test_endpoint(
        "Missing required field (product_type)",
        "POST",
        "/v1/policies",
        422,
        payload=missing_product
    )

    # Missing effective_date
    missing_effective = valid_policy.copy()
    del missing_effective["effective_date"]
    test_endpoint(
        "Missing required field (effective_date)",
        "POST",
        "/v1/policies",
        422,
        payload=missing_effective
    )

    # Missing expiration_date
    missing_expiration = valid_policy.copy()
    del missing_expiration["expiration_date"]
    test_endpoint(
        "Missing required field (expiration_date)",
        "POST",
        "/v1/policies",
        422,
        payload=missing_expiration
    )

    # Missing premium_amount
    missing_premium = valid_policy.copy()
    del missing_premium["premium_amount"]
    test_endpoint(
        "Missing required field (premium_amount)",
        "POST",
        "/v1/policies",
        422,
        payload=missing_premium
    )

    # Test 6: Invalid Data
    print_section("TEST 6: Invalid Data")

    # Invalid date range (effective > expiration)
    invalid_dates = valid_policy.copy()
    invalid_dates["effective_date"] = expiration_date
    invalid_dates["expiration_date"] = effective_date
    test_endpoint(
        "Invalid date range (effective > expiration)",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_dates,
        notes="Effective date must be before expiration date"
    )

    # Negative premium
    negative_premium = valid_policy.copy()
    negative_premium["premium_amount"] = "-100.00"
    test_endpoint(
        "Negative premium amount",
        "POST",
        "/v1/policies",
        422,
        payload=negative_premium
    )

    # Zero premium
    zero_premium = valid_policy.copy()
    zero_premium["premium_amount"] = "0.00"
    test_endpoint(
        "Zero premium amount",
        "POST",
        "/v1/policies",
        422,
        payload=zero_premium,
        notes="Premium must be positive"
    )

    # Invalid customer_id format (wrong prefix)
    invalid_customer_prefix = valid_policy.copy()
    invalid_customer_prefix["customer_id"] = "cust_01HQZK9X1Z2Y3W4V5U6T7S8R9"
    test_endpoint(
        "Invalid customer_id prefix (cust_ instead of cus_)",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_customer_prefix
    )

    # Invalid customer_id length
    invalid_customer_length = valid_policy.copy()
    invalid_customer_length["customer_id"] = "cus_short"
    test_endpoint(
        "Invalid customer_id length",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_customer_length,
        notes="Customer ID must be exactly 30 characters"
    )

    # Invalid currency code
    invalid_currency = valid_policy.copy()
    invalid_currency["currency"] = "USDD"
    test_endpoint(
        "Invalid currency code (4 chars instead of 3)",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_currency
    )

    # Invalid product_type
    invalid_product_type = valid_policy.copy()
    invalid_product_type["product_type"] = "invalid_type"
    test_endpoint(
        "Invalid product_type enum value",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_product_type
    )

    # Invalid status
    invalid_status = valid_policy.copy()
    invalid_status["status"] = "invalid_status"
    test_endpoint(
        "Invalid status enum value",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_status
    )

    # Invalid billing_frequency
    invalid_billing = valid_policy.copy()
    invalid_billing["billing_frequency"] = "weekly"
    test_endpoint(
        "Invalid billing_frequency enum value",
        "POST",
        "/v1/policies",
        422,
        payload=invalid_billing
    )

    # Test 7: Get Policy by ID
    print_section("TEST 7: Get Policy by ID")

    if created_policy_id:
        test_endpoint(
            f"Get created policy by ID: {created_policy_id}",
            "GET",
            f"/v1/policies/{created_policy_id}",
            200,
            notes="Should return full policy details"
        )
    else:
        print("⚠️  Skipping: No policy was created successfully\n")

    # Get non-existent policy
    test_endpoint(
        "Get non-existent policy",
        "GET",
        "/v1/policies/pol_nonexistent1234567890",
        404,
        notes="Should return 404 Not Found"
    )

    # Test 8: Update Policy (PATCH)
    print_section("TEST 8: Update Policy (PATCH)")

    if created_policy_id:
        update_data = {
            "status": "active",
            "premium_amount": "1300.00",
            "metadata": {
                "updated": True,
                "test": "patch_operation"
            }
        }
        test_endpoint(
            f"Update policy {created_policy_id}",
            "PATCH",
            f"/v1/policies/{created_policy_id}",
            200,
            payload=update_data,
            notes="Partial update of policy fields"
        )
    else:
        print("⚠️  Skipping: No policy was created successfully\n")

    # Test 9: Policy Evaluation
    print_section("TEST 9: Policy Evaluation (Cedar)")

    evaluate_payload = {
        "policy_id": created_policy_id or "pol_test",
        "principal": {
            "type": "User",
            "id": "test-admin-user"
        },
        "action": {
            "type": "Action",
            "id": "view"
        },
        "resource": {
            "type": "Policy",
            "id": created_policy_id or "pol_test"
        },
        "context": {
            "organization_id": "test-org-001",
            "timestamp": datetime.now().isoformat() + "Z"
        }
    }

    test_endpoint(
        "Evaluate policy (single)",
        "POST",
        "/v1/policies/evaluate",
        200,
        payload=evaluate_payload,
        notes="Test Cedar policy evaluation. May fail if evaluate endpoint not implemented."
    )

    # Test 10: Batch Evaluation
    print_section("TEST 10: Batch Policy Evaluation")

    batch_payload = {
        "evaluations": [evaluate_payload]
    }

    test_endpoint(
        "Batch evaluate policies",
        "POST",
        "/v1/policies/evaluate/batch",
        200,
        payload=batch_payload,
        notes="Test batch evaluation endpoint"
    )

    # Test 11: Delete Policy
    print_section("TEST 11: Delete Policy")

    if created_policy_id:
        test_endpoint(
            f"Delete policy {created_policy_id}",
            "DELETE",
            f"/v1/policies/{created_policy_id}",
            204,
            notes="Soft delete (sets deleted_at). Should return 204 No Content."
        )

        # Verify policy is deleted (should return 404)
        test_endpoint(
            "Verify deleted policy returns 404",
            "GET",
            f"/v1/policies/{created_policy_id}",
            404,
            notes="Deleted policy should not be retrievable"
        )
    else:
        print("⚠️  Skipping: No policy was created successfully\n")

    # Print Summary
    print_section("TEST SUMMARY")

    total_tests = len(test_results)
    passed_tests = sum(1 for t in test_results if t.passed)
    failed_tests = total_tests - passed_tests
    success_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0

    print(f"Total Tests:     {total_tests}")
    print(f"\033[92mPassed Tests:    {passed_tests}\033[0m")
    print(f"\033[91mFailed Tests:    {failed_tests}\033[0m")
    print(f"Success Rate:    {success_rate:.1f}%\n")

    # Detailed failures
    if failed_tests > 0:
        print_section("FAILED TESTS DETAILS")
        for result in test_results:
            if not result.passed:
                print(f"✗ {result.test_name}")
                print(f"  {result.method} {result.endpoint}")
                print(f"  Expected: {result.expected_status}, Got: {result.status_code}")
                if result.notes:
                    print(f"  Notes: {result.notes}")
                if isinstance(result.response_body, dict):
                    print(f"  Response: {json.dumps(result.response_body, indent=2)[:300]}")
                print()

    # Endpoint Coverage
    print_section("ENDPOINT COVERAGE")
    endpoints_tested = set(f"{r.method} {r.endpoint}" for r in test_results)
    for endpoint in sorted(endpoints_tested):
        print(f"  {endpoint}")

    print(f"\nTotal Unique Endpoints Tested: {len(endpoints_tested)}\n")

    # Issues Found
    print_section("ISSUES FOUND")

    issues = []

    # Check for 500 errors
    internal_errors = [r for r in test_results if r.status_code == 500]
    if internal_errors:
        issues.append({
            "severity": "CRITICAL",
            "issue": "Internal Server Errors (500)",
            "count": len(internal_errors),
            "endpoints": list(set(f"{r.method} {r.endpoint}" for r in internal_errors)),
            "description": "Service returning 500 errors. Likely database connection or missing tables."
        })

    # Check if policy creation works
    creation_tests = [r for r in test_results if r.endpoint == "/v1/policies" and r.method == "POST" and r.expected_status == 201]
    if creation_tests and not any(t.passed for t in creation_tests):
        issues.append({
            "severity": "CRITICAL",
            "issue": "Policy Creation Not Working",
            "description": "Cannot create policies. Core functionality is broken."
        })

    # Check if list endpoint works
    list_tests = [r for r in test_results if r.endpoint == "/v1/policies" and r.method == "GET"]
    if list_tests and not any(t.passed for t in list_tests):
        issues.append({
            "severity": "HIGH",
            "issue": "List Policies Endpoint Not Working",
            "description": "Cannot retrieve policy lists."
        })

    if issues:
        for i, issue in enumerate(issues, 1):
            print(f"{i}. [{issue['severity']}] {issue['issue']}")
            print(f"   {issue['description']}")
            if "endpoints" in issue:
                print(f"   Affected Endpoints: {', '.join(issue['endpoints'])}")
            print()
    else:
        print("\033[92m✓ No critical issues found! All tests passed.\033[0m\n")

    print_section("RECOMMENDATIONS")

    if internal_errors:
        print("1. Check database connectivity and ensure DATABASE_URL is configured correctly")
        print("2. Verify database migrations have been run")
        print("3. Check service logs for detailed error messages")
        print("4. Ensure required database schemas and tables exist")
    elif not created_policy_id:
        print("1. Policy creation is failing - investigate service logic")
        print("2. Check for any business logic errors in PolicyService")
    else:
        print("\033[92m✓ Service is functioning correctly!")
        print("✓ Auth stub is working (no authentication needed)")
        print("✓ Validation is working correctly")
        print("✓ CRUD operations are functional\033[0m")

    print()

    return 0 if failed_tests == 0 else 1


if __name__ == "__main__":
    sys.exit(main())
