import os
from typing import List, Optional

from fastapi import APIRouter, Query, Body, HTTPException

from boaviztapi import config, data_dir
from boaviztapi.dto.device.user_terminal import (
    UserTerminal,
    VrHeadset,
    mapper_user_terminal,
    Laptop,
    Desktop,
    Smartphone,
    Television,
    Tablet,
    Box,
)
from boaviztapi.routers.openapi_doc.descriptions import (
    all_archetype_user_terminals,
    all_terminal_categories,
    get_archetype_config_desc,
    terminal_description,
)
from boaviztapi.routers.openapi_doc.examples import end_user_terminal
from boaviztapi.service.archetype import (
    get_user_terminal_archetype,
    get_device_archetype_lst_with_type,
)
from boaviztapi.service.impacts_computation import compute_impacts
from boaviztapi.service.verbose import verbose_device

terminal_router = APIRouter(prefix="/v1/terminal", tags=["terminal"])


@terminal_router.get("/all", description=all_terminal_categories)
async def terminal_get_all_categories():
    return {
        "laptop": "v1/terminal/laptop",
        "desktop": "v1/terminal/desktop",
        "smartphone": "v1/terminal/smartphone",
        "television": "v1/terminal/television",
        "tablet": "v1/terminal/tablet",
        "box": "v1/terminal/box",
        "vr_headset": "v1/terminal/vr_headset",
    }


@terminal_router.get("/laptop/archetypes", description=all_archetype_user_terminals)
async def laptop_get_all_archetype_name():
    return get_all_archetype_name("laptop")


@terminal_router.get("/laptop/archetype_config", description=get_archetype_config_desc)
async def laptop_get_archetype_config(
    archetype: str = Query(example=config["default_laptop"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/laptop", description=terminal_description)
async def laptop_impact(
    laptop: Laptop = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_laptop"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=laptop,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/laptop", description=terminal_description)
async def laptop_impact(
    archetype: str = config["default_laptop"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Laptop(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/desktop/archetypes", description=all_archetype_user_terminals)
async def desktop_get_all_archetype_name():
    return get_all_archetype_name("desktop")


@terminal_router.get("/desktop/archetype_config", description=get_archetype_config_desc)
async def desktop_get_archetype_config(
    archetype: str = Query(example=config["default_desktop"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/desktop", description=terminal_description)
async def desktop_impact(
    desktop: Desktop = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_desktop"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=desktop,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/desktop", description=terminal_description)
async def desktop_impact(
    archetype: str = config["default_desktop"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Desktop(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/smartphone/archetypes", description=all_archetype_user_terminals)
async def smartphone_get_all_archetype_name():
    return get_all_archetype_name("smartphone")


@terminal_router.get(
    "/smartphone/archetype_config", description=get_archetype_config_desc
)
async def smartphone_get_archetype_config(
    archetype: str = Query(example=config["default_smartphone"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/smartphone", description=terminal_description)
async def smartphone_impact(
    smartphone: Smartphone = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_smartphone"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=smartphone,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/smartphone", description=terminal_description)
async def smartphone_impact(
    archetype: str = config["default_smartphone"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Smartphone(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/tablet/archetypes", description=all_archetype_user_terminals)
async def tablet_get_all_archetype_name():
    return get_all_archetype_name("tablet")


@terminal_router.get("/tablet/archetype_config", description=get_archetype_config_desc)
async def tablet_get_archetype_config(
    archetype: str = Query(example=config["default_tablet"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/tablet", description=terminal_description)
async def tablet_impact(
    tablet: Tablet = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_tablet"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=tablet,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/tablet", description=terminal_description)
async def tablet_impact(
    archetype: str = config["default_tablet"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Tablet(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/television/archetypes", description=all_archetype_user_terminals)
async def television_get_all_archetype_name():
    return get_all_archetype_name("television")


@terminal_router.get(
    "/television/archetype_config", description=get_archetype_config_desc
)
async def television_get_archetype_config(
    archetype: str = Query(example=config["default_television"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/television", description=terminal_description)
async def television_impact(
    television: Television = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_television"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=television,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/television", description=terminal_description)
async def television_impact(
    archetype: str = config["default_television"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Television(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/box/archetypes", description=all_archetype_user_terminals)
async def box_get_all_archetype_name():
    return get_all_archetype_name("box")


@terminal_router.get("/box/archetype_config", description=get_archetype_config_desc)
async def box_get_archetype_config(
    archetype: str = Query(example=config["default_box"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/box", description=terminal_description)
async def box_impact(
    box: Box = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_box"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=box,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/box", description=terminal_description)
async def box_impact(
    archetype: str = config["default_box"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=Box(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/vr_headset/archetypes", description=all_archetype_user_terminals)
async def vr_headset_get_all_archetype_name():
    return get_all_archetype_name("vr_headset")


@terminal_router.get(
    "/vr_headset/archetype_config", description=get_archetype_config_desc
)
async def vr_headset_get_archetype_config(
    archetype: str = Query(example=config["default_vr_headset"]),
):
    return get_archetype_config(archetype)


@terminal_router.post("/vr_headset", description=terminal_description)
async def vr_headset_impact_from_configuration(
    vr_headset: VrHeadset = Body(None, example=end_user_terminal),
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    archetype: str = config["default_vr_headset"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=vr_headset,
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


@terminal_router.get("/vr_headset", description=terminal_description)
async def vr_headset_impact(
    archetype: str = config["default_vr_headset"],
    verbose: bool = True,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
):
    return await user_terminal_impact(
        user_terminal_dto=VrHeadset(),
        verbose=verbose,
        duration=duration,
        criteria=criteria,
        archetype=archetype,
    )


async def user_terminal_impact(
    user_terminal_dto: UserTerminal,
    archetype: str,
    verbose: bool,
    duration: Optional[float] = config["default_duration"],
    criteria: List[str] = Query(config["default_criteria"]),
) -> dict:
    archetype_config = get_user_terminal_archetype(archetype)

    if not archetype_config:
        raise HTTPException(status_code=404, detail=f"{archetype} not found")

    device = mapper_user_terminal(user_terminal_dto, archetype=archetype_config)

    if duration is None:
        duration = device.usage.hours_life_time.value

    impacts = compute_impacts(
        model=device, selected_criteria=criteria, duration=duration
    )

    if verbose:
        return {
            "impacts": impacts,
            "verbose": verbose_device(
                device, selected_criteria=criteria, duration=duration
            ),
        }

    return {"impacts": impacts}


def get_all_archetype_name(name: str):
    result = get_device_archetype_lst_with_type(
        os.path.join(data_dir, "archetypes/user_terminal.csv"), name.lower()
    )
    if not result:
        return None
    return result


def get_archetype_config(archetype: str):
    result = get_user_terminal_archetype(archetype)
    if not result:
        raise HTTPException(status_code=404, detail=f"{archetype} not found")
    return result
