#!/usr/bin/env python3
"""
Backend API Testing Script for Horse Racing Tips App
Tests all API endpoints with realistic data
"""

import requests
import json
import sys
from datetime import datetime, timedelta
import uuid

# Get backend URL from frontend env
BACKEND_URL = "https://raceadvisor.preview.emergentagent.com/api"


class Colors:
    GREEN = "\033[92m"
    RED = "\033[91m"
    YELLOW = "\033[93m"
    BLUE = "\033[94m"
    ENDC = "\033[0m"
    BOLD = "\033[1m"


def log_test(test_name, status, details=""):
    """Log test results with colors"""
    color = (
        Colors.GREEN
        if status == "PASS"
        else Colors.RED if status == "FAIL" else Colors.YELLOW
    )
    print(f"{color}{status}{Colors.ENDC} - {test_name}")
    if details:
        print(f"  {details}")


def test_api_root():
    """Test GET /api/ - API info"""
    try:
        response = requests.get(f"{BACKEND_URL}/")
        if response.status_code == 200:
            data = response.json()
            if "message" in data and "version" in data:
                log_test(
                    "API Root Endpoint",
                    "PASS",
                    f"Message: {data['message']}, Version: {data['version']}",
                )
                return True
            else:
                log_test(
                    "API Root Endpoint", "FAIL", "Missing required fields in response"
                )
                return False
        else:
            log_test("API Root Endpoint", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("API Root Endpoint", "FAIL", f"Exception: {str(e)}")
        return False


def test_health_check():
    """Test GET /api/health - Health check"""
    try:
        response = requests.get(f"{BACKEND_URL}/health")
        if response.status_code == 200:
            data = response.json()
            if data.get("status") == "healthy":
                log_test("Health Check", "PASS", "Service is healthy")
                return True
            else:
                log_test("Health Check", "FAIL", f"Unexpected status: {data}")
                return False
        else:
            log_test("Health Check", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Health Check", "FAIL", f"Exception: {str(e)}")
        return False


def test_get_races():
    """Test GET /api/races - Get list of upcoming races"""
    try:
        # Test basic races endpoint
        response = requests.get(f"{BACKEND_URL}/races")
        if response.status_code == 200:
            races = response.json()
            if isinstance(races, list) and len(races) > 0:
                race = races[0]
                required_fields = [
                    "id",
                    "track",
                    "race_number",
                    "start_time",
                    "distance",
                    "race_class",
                    "conditions",
                    "horse_count",
                ]
                if all(field in race for field in required_fields):
                    log_test(
                        "Get Races - Basic", "PASS", f"Retrieved {len(races)} races"
                    )

                    # Test with filters
                    test_filters(races[0]["id"])
                    return True
                else:
                    missing = [f for f in required_fields if f not in race]
                    log_test("Get Races - Basic", "FAIL", f"Missing fields: {missing}")
                    return False
            else:
                log_test(
                    "Get Races - Basic", "FAIL", "No races returned or invalid format"
                )
                return False
        else:
            log_test("Get Races - Basic", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Get Races - Basic", "FAIL", f"Exception: {str(e)}")
        return False


def test_filters(sample_race_id):
    """Test race filters"""
    try:
        # Test date filter
        response = requests.get(f"{BACKEND_URL}/races?date=today")
        if response.status_code == 200:
            log_test("Get Races - Date Filter", "PASS", f"Today filter works")
        else:
            log_test(
                "Get Races - Date Filter", "FAIL", f"Status: {response.status_code}"
            )

        # Test track filter
        response = requests.get(f"{BACKEND_URL}/races?track=Flemington")
        if response.status_code == 200:
            log_test("Get Races - Track Filter", "PASS", f"Track filter works")
        else:
            log_test(
                "Get Races - Track Filter", "FAIL", f"Status: {response.status_code}"
            )

    except Exception as e:
        log_test("Get Races - Filters", "FAIL", f"Exception: {str(e)}")


def test_next_upcoming_race():
    """Test GET /api/races/next/upcoming - Get next upcoming race"""
    try:
        response = requests.get(f"{BACKEND_URL}/races/next/upcoming")
        if response.status_code == 200:
            race = response.json()
            required_fields = ["id", "track", "race_number", "start_time", "horses"]
            if all(field in race for field in required_fields):
                if isinstance(race["horses"], list) and len(race["horses"]) > 0:
                    horse = race["horses"][0]
                    horse_fields = [
                        "id",
                        "number",
                        "name",
                        "jockey",
                        "trainer",
                        "win_probability",
                        "place_probability",
                    ]
                    if all(field in horse for field in horse_fields):
                        log_test(
                            "Next Upcoming Race",
                            "PASS",
                            f"Race: {race['track']} R{race['race_number']}, {len(race['horses'])} horses",
                        )
                        return race["id"]  # Return race ID for other tests
                    else:
                        missing = [f for f in horse_fields if f not in horse]
                        log_test(
                            "Next Upcoming Race",
                            "FAIL",
                            f"Horse missing fields: {missing}",
                        )
                        return None
                else:
                    log_test("Next Upcoming Race", "FAIL", "No horses in race")
                    return None
            else:
                missing = [f for f in required_fields if f not in race]
                log_test("Next Upcoming Race", "FAIL", f"Missing fields: {missing}")
                return None
        else:
            log_test("Next Upcoming Race", "FAIL", f"Status: {response.status_code}")
            return None
    except Exception as e:
        log_test("Next Upcoming Race", "FAIL", f"Exception: {str(e)}")
        return None


def test_generate_tip(race_id):
    """Test POST /api/tips/generate - Generate a tip"""
    try:
        # Test different bet types
        bet_types = ["best_bet", "win", "place", "quinella", "exacta", "trifecta"]

        for bet_type in bet_types:
            payload = {"race_id": race_id or "test_race_123", "bet_type": bet_type}

            response = requests.post(f"{BACKEND_URL}/tips/generate", json=payload)
            if response.status_code == 200:
                tip = response.json()
                required_fields = [
                    "id",
                    "race_id",
                    "bet_type",
                    "recommended_bet",
                    "confidence",
                    "horses",
                    "reasons",
                    "created_at",
                ]
                if all(field in tip for field in required_fields):
                    if isinstance(tip["horses"], list) and len(tip["horses"]) > 0:
                        if isinstance(tip["reasons"], list) and len(tip["reasons"]) > 0:
                            log_test(
                                f"Generate Tip - {bet_type}",
                                "PASS",
                                f"Confidence: {tip['confidence']}, Bet: {tip['recommended_bet'][:50]}...",
                            )
                        else:
                            log_test(
                                f"Generate Tip - {bet_type}",
                                "FAIL",
                                "No reasons provided",
                            )
                    else:
                        log_test(
                            f"Generate Tip - {bet_type}", "FAIL", "No horses in tip"
                        )
                else:
                    missing = [f for f in required_fields if f not in tip]
                    log_test(
                        f"Generate Tip - {bet_type}",
                        "FAIL",
                        f"Missing fields: {missing}",
                    )
            else:
                log_test(
                    f"Generate Tip - {bet_type}",
                    "FAIL",
                    f"Status: {response.status_code}",
                )

        return True
    except Exception as e:
        log_test("Generate Tip", "FAIL", f"Exception: {str(e)}")
        return False


def test_save_and_get_tips():
    """Test POST /api/tips/save and GET /api/tips/saved"""
    try:
        # Create a sample tip to save
        sample_tip = {
            "id": str(uuid.uuid4()),
            "race_id": "melbourne_cup_2024",
            "bet_type": "win",
            "recommended_bet": "WIN on #7 Thunder Bolt",
            "confidence": "high",
            "horses": [
                {
                    "id": str(uuid.uuid4()),
                    "number": 7,
                    "name": "Thunder Bolt",
                    "jockey": "J. McDonald",
                    "trainer": "C. Waller",
                    "win_probability": 28.5,
                    "place_probability": 65.2,
                }
            ],
            "reasons": [
                {"text": "Strong recent form", "type": "positive"},
                {"text": "Top jockey in the saddle", "type": "positive"},
            ],
            "created_at": datetime.utcnow().isoformat(),
        }

        # Test saving tip
        response = requests.post(f"{BACKEND_URL}/tips/save", json=sample_tip)
        if response.status_code == 200:
            saved_tip = response.json()
            if "id" in saved_tip and "saved_at" in saved_tip:
                log_test("Save Tip", "PASS", f"Tip saved with ID: {saved_tip['id']}")

                # Test getting saved tips
                response = requests.get(f"{BACKEND_URL}/tips/saved")
                if response.status_code == 200:
                    saved_tips = response.json()
                    if isinstance(saved_tips, list):
                        log_test(
                            "Get Saved Tips",
                            "PASS",
                            f"Retrieved {len(saved_tips)} saved tips",
                        )
                        return True
                    else:
                        log_test("Get Saved Tips", "FAIL", "Invalid response format")
                        return False
                else:
                    log_test(
                        "Get Saved Tips", "FAIL", f"Status: {response.status_code}"
                    )
                    return False
            else:
                log_test("Save Tip", "FAIL", "Missing required fields in response")
                return False
        else:
            log_test("Save Tip", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Save/Get Tips", "FAIL", f"Exception: {str(e)}")
        return False


def test_schedules_crud():
    """Test POST /api/schedules, GET /api/schedules, DELETE /api/schedules/{id}"""
    try:
        # Create a schedule
        schedule_data = {
            "race_id": "flemington_race_456",
            "bet_type": "win",
            "minutes_before": 15,
            "channels": ["push"],
        }

        response = requests.post(f"{BACKEND_URL}/schedules", json=schedule_data)
        if response.status_code == 200:
            schedule = response.json()
            required_fields = [
                "id",
                "race_id",
                "bet_type",
                "minutes_before",
                "channels",
                "status",
                "scheduled_time",
            ]
            if all(field in schedule for field in required_fields):
                schedule_id = schedule["id"]
                log_test(
                    "Create Schedule",
                    "PASS",
                    f"Schedule created with ID: {schedule_id}",
                )

                # Test getting schedules
                response = requests.get(f"{BACKEND_URL}/schedules")
                if response.status_code == 200:
                    schedules = response.json()
                    if isinstance(schedules, list):
                        log_test(
                            "Get Schedules",
                            "PASS",
                            f"Retrieved {len(schedules)} schedules",
                        )

                        # Test deleting schedule
                        response = requests.delete(
                            f"{BACKEND_URL}/schedules/{schedule_id}"
                        )
                        if response.status_code == 200:
                            result = response.json()
                            if "message" in result:
                                log_test(
                                    "Delete Schedule",
                                    "PASS",
                                    "Schedule cancelled successfully",
                                )
                                return True
                            else:
                                log_test(
                                    "Delete Schedule", "FAIL", "No confirmation message"
                                )
                                return False
                        else:
                            log_test(
                                "Delete Schedule",
                                "FAIL",
                                f"Status: {response.status_code}",
                            )
                            return False
                    else:
                        log_test("Get Schedules", "FAIL", "Invalid response format")
                        return False
                else:
                    log_test("Get Schedules", "FAIL", f"Status: {response.status_code}")
                    return False
            else:
                missing = [f for f in required_fields if f not in schedule]
                log_test("Create Schedule", "FAIL", f"Missing fields: {missing}")
                return False
        else:
            log_test("Create Schedule", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Schedules CRUD", "FAIL", f"Exception: {str(e)}")
        return False


def test_user_preferences():
    """Test GET /api/user/preferences and PUT /api/user/preferences"""
    try:
        # Test getting preferences
        response = requests.get(f"{BACKEND_URL}/user/preferences")
        if response.status_code == 200:
            prefs = response.json()
            required_fields = [
                "id",
                "default_bet_type",
                "default_lead_time",
                "favorite_tracks",
                "notification_channels",
            ]
            if all(field in prefs for field in required_fields):
                log_test(
                    "Get User Preferences",
                    "PASS",
                    f"Default bet type: {prefs['default_bet_type']}",
                )

                # Test updating preferences
                updates = {
                    "default_bet_type": "place",
                    "default_lead_time": 30,
                    "favorite_tracks": ["Flemington", "Randwick"],
                }

                response = requests.put(f"{BACKEND_URL}/user/preferences", json=updates)
                if response.status_code == 200:
                    updated_prefs = response.json()
                    if updated_prefs.get("default_bet_type") == "place":
                        log_test(
                            "Update User Preferences",
                            "PASS",
                            "Preferences updated successfully",
                        )
                        return True
                    else:
                        log_test(
                            "Update User Preferences", "FAIL", "Updates not reflected"
                        )
                        return False
                else:
                    log_test(
                        "Update User Preferences",
                        "FAIL",
                        f"Status: {response.status_code}",
                    )
                    return False
            else:
                missing = [f for f in required_fields if f not in prefs]
                log_test("Get User Preferences", "FAIL", f"Missing fields: {missing}")
                return False
        else:
            log_test("Get User Preferences", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("User Preferences", "FAIL", f"Exception: {str(e)}")
        return False


def test_tracks():
    """Test GET /api/tracks - Get available tracks"""
    try:
        response = requests.get(f"{BACKEND_URL}/tracks")
        if response.status_code == 200:
            data = response.json()
            if (
                "tracks" in data
                and isinstance(data["tracks"], list)
                and len(data["tracks"]) > 0
            ):
                log_test(
                    "Get Tracks", "PASS", f"Retrieved {len(data['tracks'])} tracks"
                )
                return True
            else:
                log_test("Get Tracks", "FAIL", "No tracks returned or invalid format")
                return False
        else:
            log_test("Get Tracks", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Get Tracks", "FAIL", f"Exception: {str(e)}")
        return False


def test_bet_types():
    """Test GET /api/bet-types - Get bet type options"""
    try:
        response = requests.get(f"{BACKEND_URL}/bet-types")
        if response.status_code == 200:
            data = response.json()
            if "simple" in data and "advanced" in data:
                simple_bets = data["simple"]
                advanced_bets = data["advanced"]
                if isinstance(simple_bets, list) and isinstance(advanced_bets, list):
                    total_bets = len(simple_bets) + len(advanced_bets)
                    log_test(
                        "Get Bet Types",
                        "PASS",
                        f"Retrieved {total_bets} bet types ({len(simple_bets)} simple, {len(advanced_bets)} advanced)",
                    )
                    return True
                else:
                    log_test("Get Bet Types", "FAIL", "Invalid bet types format")
                    return False
            else:
                log_test("Get Bet Types", "FAIL", "Missing simple/advanced categories")
                return False
        else:
            log_test("Get Bet Types", "FAIL", f"Status: {response.status_code}")
            return False
    except Exception as e:
        log_test("Get Bet Types", "FAIL", f"Exception: {str(e)}")
        return False


def test_error_handling():
    """Test error handling for invalid requests"""
    try:
        # Test invalid race ID
        response = requests.get(f"{BACKEND_URL}/races/invalid_race_id")
        if response.status_code == 404:
            log_test(
                "Error Handling - Invalid Race", "PASS", "404 returned for invalid race"
            )
        else:
            log_test(
                "Error Handling - Invalid Race",
                "FAIL",
                f"Expected 404, got {response.status_code}",
            )

        # Test invalid schedule deletion
        response = requests.delete(f"{BACKEND_URL}/schedules/invalid_schedule_id")
        if response.status_code == 404:
            log_test(
                "Error Handling - Invalid Schedule",
                "PASS",
                "404 returned for invalid schedule",
            )
        else:
            log_test(
                "Error Handling - Invalid Schedule",
                "FAIL",
                f"Expected 404, got {response.status_code}",
            )

        return True
    except Exception as e:
        log_test("Error Handling", "FAIL", f"Exception: {str(e)}")
        return False


def main():
    """Run all backend API tests"""
    print(
        f"{Colors.BOLD}{Colors.BLUE}=== Horse Racing Tips API Backend Tests ==={Colors.ENDC}"
    )
    print(f"Testing backend at: {BACKEND_URL}")
    print()

    test_results = []

    # Core API tests
    test_results.append(test_api_root())
    test_results.append(test_health_check())

    # Race endpoints
    test_results.append(test_get_races())
    race_id = test_next_upcoming_race()
    test_results.append(race_id is not None)

    # Tip endpoints
    test_results.append(test_generate_tip(race_id))
    test_results.append(test_save_and_get_tips())

    # Schedule endpoints
    test_results.append(test_schedules_crud())

    # User preferences
    test_results.append(test_user_preferences())

    # Reference data
    test_results.append(test_tracks())
    test_results.append(test_bet_types())

    # Error handling
    test_results.append(test_error_handling())

    # Summary
    passed = sum(test_results)
    total = len(test_results)

    print()
    print(f"{Colors.BOLD}=== Test Summary ==={Colors.ENDC}")
    if passed == total:
        print(f"{Colors.GREEN}✅ All {total} tests passed!{Colors.ENDC}")
        return 0
    else:
        failed = total - passed
        print(f"{Colors.RED}❌ {failed} out of {total} tests failed{Colors.ENDC}")
        print(f"{Colors.GREEN}✅ {passed} tests passed{Colors.ENDC}")
        return 1


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