"""Main app for backend api"""
import logging
import time
import random
from fastapi import HTTPException, APIRouter

from ..structs.landmark import Landmark
from ..structs.preferences import Preferences, Preference
from .landmarks_manager import LandmarkManager


# Setup the logger and the Landmarks Manager
logger = logging.getLogger(__name__)
manager = LandmarkManager()


# Initialize the API router
router = APIRouter()


@router.post("/get/landmarks")
def get_landmarks(
    preferences: Preferences,
    start: tuple[float, float],
) -> list[Landmark]:
    """
    Function that returns all available landmarks given some preferences and a start position.

    Args:
        preferences : the preferences specified by the user as the post body
        start       : the coordinates of the starting point
    Returns: 
        list[Landmark] : The full list of fetched landmarks
    """
    if preferences is None:
        raise HTTPException(status_code=406, detail="Preferences not provided or incomplete.")
    if (preferences.shopping.score == 0 and
        preferences.sightseeing.score == 0 and
        preferences.nature.score == 0) :
        raise HTTPException(status_code=406, detail="All preferences are 0.")
    if start is None:
        raise HTTPException(status_code=406, detail="Start coordinates not provided")
    if not (-90 <= start[0] <= 90 or -180 <= start[1] <= 180):
        raise HTTPException(status_code=422, detail="Start coordinates not in range")

    logger.info(f"Requested new trip generation. Details:\n\tCoordinates: {start}\n\tTime: {preferences.max_time_minute}\n\tSightseeing: {preferences.sightseeing.score}\n\tNature: {preferences.nature.score}\n\tShopping: {preferences.shopping.score}")

    start_time = time.time()

    # Generate the landmarks from the start location
    landmarks = manager.generate_landmarks_list(
        center_coordinates = start,
        preferences = preferences
    )

    if len(landmarks) == 0 :
        raise HTTPException(status_code=500, detail="No landmarks were found.")

    t_generate_landmarks = time.time() - start_time
    logger.info(f'Fetched {len(landmarks)} landmarks in  \t: {round(t_generate_landmarks,3)} seconds')
    
    return landmarks


@router.post("/get-nearby/landmarks/{lat}/{lon}")
def get_landmarks_nearby(
    lat: float,
    lon: float
) -> list[Landmark] :
    """
    Suggests nearby landmarks based on a given latitude and longitude.

    This endpoint returns a curated list of up to 5 landmarks around the given geographical coordinates. It uses fixed preferences for
    sightseeing, shopping, and nature, with a maximum time constraint of 30 minutes to limit the number of landmarks returned.

    Args:
        lat (float): Latitude of the user's current location.
        lon (float): Longitude of the user's current location.

    Returns:
        list[Landmark]: A list of selected nearby landmarks.
    """
    logger.info(f'Fetching landmarks nearby ({lat}, {lon}).')

    # Define fixed preferences:
    prefs = Preferences(
        sightseeing = Preference(
            type='sightseeing',
            score=5
        ),
        shopping = Preference(
            type='shopping',
            score=2
        ),
        nature = Preference(
            type='nature',
            score=5
        ),
        max_time_minute=30,
        detour_tolerance_minute=0,
    )

    # Find the landmarks around the location
    landmarks_around = manager.generate_landmarks_list(
        center_coordinates = (lat, lon),
        preferences = prefs,
        allow_clusters=False,
    )

    if len(landmarks_around) == 0 :
        raise HTTPException(status_code=500, detail="No landmarks were found.")

    # select 8 - 12 landmarks from there
    if len(landmarks_around) > 8 :
        n_imp = random.randint(2,5)
        rest = random.randint(8 - n_imp, min(12, len(landmarks_around))-n_imp)

        print(f'len = {len(landmarks_around)}\nn_imp = {n_imp}\nrest = {rest}')
        landmarks_around = landmarks_around[:n_imp] + random.sample(landmarks_around[n_imp:], rest)
    
    logger.info(f'Found {len(landmarks_around)} landmarks to suggest nearby ({lat}, {lon}).')
    # logger.debug('Suggested landmarks :\n\t' + '\n\t'.join(f'{landmark}' for landmark in landmarks_around))
    return landmarks_around
