#
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from gns3server.controller.gns3vm.gns3_vm_error import GNS3VMError
from gns3server.compute.error import ImageMissingError, NodeError
from gns3server.compute.ubridge.ubridge_error import UbridgeError

from gns3server.compute.compute_error import (
    ComputeError,
    ComputeNotFoundError,
    ComputeTimeoutError,
    ComputeForbiddenError,
    ComputeUnauthorizedError
)

from . import capabilities
from . import compute
from . import projects
from . import notifications
from . import images
from . import atm_switch_nodes
from . import cloud_nodes
from . import docker_nodes
from . import dynamips_nodes
from . import ethernet_hub_nodes
from . import ethernet_switch_nodes
from . import frame_relay_switch_nodes
from . import iou_nodes
from . import nat_nodes
from . import qemu_nodes
from . import virtualbox_nodes
from . import vmware_nodes
from . import vpcs_nodes


compute_api = FastAPI(title="GNS3 compute API",
                      description="This page describes the private compute API for GNS3. PLEASE DO NOT USE DIRECTLY!",
                      version="v3")


@compute_api.exception_handler(ComputeError)
async def controller_error_handler(request: Request, exc: ComputeError):
    return JSONResponse(
        status_code=409,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(ComputeTimeoutError)
async def controller_timeout_error_handler(request: Request, exc: ComputeTimeoutError):
    return JSONResponse(
        status_code=408,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(ComputeUnauthorizedError)
async def controller_unauthorized_error_handler(request: Request, exc: ComputeUnauthorizedError):
    return JSONResponse(
        status_code=401,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(ComputeForbiddenError)
async def controller_forbidden_error_handler(request: Request, exc: ComputeForbiddenError):
    return JSONResponse(
        status_code=403,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(ComputeNotFoundError)
async def controller_not_found_error_handler(request: Request, exc: ComputeNotFoundError):
    return JSONResponse(
        status_code=404,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(GNS3VMError)
async def controller_error_handler(request: Request, exc: GNS3VMError):
    return JSONResponse(
        status_code=409,
        content={"message": str(exc)},
    )


@compute_api.exception_handler(ImageMissingError)
async def image_missing_error_handler(request: Request, exc: ImageMissingError):
    return JSONResponse(
        status_code=409,
        content={"message": str(exc), "image": exc.image, "exception": exc.__class__.__name__},
    )


@compute_api.exception_handler(NodeError)
async def node_error_handler(request: Request, exc: NodeError):
    return JSONResponse(
        status_code=409,
        content={"message": str(exc), "exception": exc.__class__.__name__},
    )


@compute_api.exception_handler(UbridgeError)
async def ubridge_error_handler(request: Request, exc: UbridgeError):
    return JSONResponse(
        status_code=409,
        content={"message": str(exc), "exception": exc.__class__.__name__},
    )


# make sure the content key is "message", not "detail" per default
@compute_api.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={"message": exc.detail},
    )


compute_api.include_router(capabilities.router, tags=["Capabilities"])
compute_api.include_router(compute.router, tags=["Compute"])
compute_api.include_router(notifications.router, tags=["Notifications"])
compute_api.include_router(projects.router, tags=["Projects"])
compute_api.include_router(images.router, tags=["Images"])
compute_api.include_router(atm_switch_nodes.router, prefix="/projects/{project_id}/atm_switch/nodes", tags=["ATM switch"])
compute_api.include_router(cloud_nodes.router, prefix="/projects/{project_id}/cloud/nodes", tags=["Cloud nodes"])
compute_api.include_router(docker_nodes.router, prefix="/projects/{project_id}/docker/nodes", tags=["Docker nodes"])
compute_api.include_router(dynamips_nodes.router, prefix="/projects/{project_id}/dynamips/nodes", tags=["Dynamips nodes"])
compute_api.include_router(ethernet_hub_nodes.router, prefix="/projects/{project_id}/ethernet_hub/nodes", tags=["Ethernet hub nodes"])
compute_api.include_router(ethernet_switch_nodes.router, prefix="/projects/{project_id}/ethernet_switch/nodes", tags=["Ethernet switch nodes"])
compute_api.include_router(frame_relay_switch_nodes.router, prefix="/projects/{project_id}/frame_relay_switch/nodes", tags=["Frame Relay switch nodes"])
compute_api.include_router(iou_nodes.router, prefix="/projects/{project_id}/iou/nodes", tags=["IOU nodes"])
compute_api.include_router(nat_nodes.router, prefix="/projects/{project_id}/nat/nodes", tags=["NAT nodes"])
compute_api.include_router(qemu_nodes.router, prefix="/projects/{project_id}/qemu/nodes", tags=["Qemu nodes"])
compute_api.include_router(virtualbox_nodes.router, prefix="/projects/{project_id}/virtualbox/nodes", tags=["VirtualBox nodes"])
compute_api.include_router(vmware_nodes.router, prefix="/projects/{project_id}/vmware/nodes", tags=["VMware nodes"])
compute_api.include_router(vpcs_nodes.router, prefix="/projects/{project_id}/vpcs/nodes", tags=["VPCS nodes"])
