"""Collection of tests to ensure correct implementation and track progress. """
import time
from fastapi.testclient import TestClient
import pytest

from .test_utils import load_trip_landmarks, log_trip_details
from ..main import app

@pytest.fixture(scope="module")
def client():
    """Client used to call the app."""
    return TestClient(app)


def test_turckheim(client, request):    # pylint: disable=redefined-outer-name
    """
    Test n°1 : Custom test in Turckheim to ensure small villages are also supported.

    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 20

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
            "nature": {"type": "nature", "score": 0},
            "shopping": {"type": "shopping", "score": 0},
            "max_time_minute": duration_minutes,
            "detour_tolerance_minute": 0},
            "start": [48.084588, 7.280405]
            # "start": [45.74445023349939, 4.8222687890538865]
            # "start": [45.75156398104873, 4.827154464827647]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])


    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)


    # checks :
    assert response.status_code == 200  # check for successful planning
    assert isinstance(landmarks, list)  # check that the return type is a list
    assert len(landmarks) > 2           # check that there is something to visit
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"
    # assert 2!= 3

def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°2 : Custom test in Lyon centre to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 120


    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 5},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [45.7576485, 4.8330241]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"

def test_cologne(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°3 : Custom test in Cologne to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 240

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 5},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [50.942352665, 6.957777972392]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"


def test_strasbourg(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°4 : Custom test in Strasbourg to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 180

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 5},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [48.5846589226, 7.74078715721]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"


def test_zurich(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°5 : Custom test in Zurich to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 180

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 5},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [47.377884227, 8.5395114066]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"


def test_paris(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°6 : Custom test in Paris (les Halles) centre to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 200

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 0},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [48.85468881798671, 2.3423925755998374]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"


def test_new_york(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°7 : Custom test in New York to ensure proper decision making in crowded area.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 600

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 5},
                            "nature": {"type": "nature", "score": 5},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [40.72592726802, -73.9920434795]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"


def test_shopping(client, request) :   # pylint: disable=redefined-outer-name
    """
    Test n°8 : Custom test in Lyon centre to ensure shopping clusters are found.
    
    Args:
        client:
        request:
    """
    start_time = time.time()  # Start timer
    duration_minutes = 240

    response = client.post(
        "/trip/new",
        json={
            "preferences": {"sightseeing": {"type": "sightseeing", "score": 0},
                            "nature": {"type": "nature", "score": 0},
                            "shopping": {"type": "shopping", "score": 5},
                            "max_time_minute": duration_minutes,
                            "detour_tolerance_minute": 0},
            "start": [45.7576485, 4.8330241]
            }
        )
    result = response.json()
    landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])

    # Get computation time
    comp_time = time.time() - start_time

    # Add details to report
    log_trip_details(request, landmarks, result['total_time'], duration_minutes)

    # for elem in landmarks :
    #     print(elem)

    # checks :
    assert response.status_code == 200  # check for successful planning
    assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
    assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}"
    assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}"
