from importlib.metadata import version

from fastapi import APIRouter
import jsonschema
from pydantic import BaseModel
import requests

router = APIRouter()


class Site(BaseModel):
    latitude: float
    longitude: float
    name: str

    @classmethod
    def from_inprov_site(cls, site: dict) -> 'Site':
        return cls(
            latitude=site['latitude'],
            longitude=site['longitude'],
            name=site['name']
        )

class SiteList(BaseModel):
    sites: list[Site]

class Router(BaseModel):
    fqdn: str
    site: str

    @classmethod
    def from_inprov_router(cls, router: dict) -> 'Router':
        return cls(
            fqdn = router['fqdn'],
            site = router['site']
        )

class RouterList(BaseModel):
    routers: list[Router]


class Endpoint(BaseModel):
    hostname: str
    interface: str

    @classmethod
    def from_inprov_endpoint(cls, endpoint: dict) -> 'Endpoint':
        return cls(
            hostname = endpoint['hostname'],
            interface = endpoint['interface'],
        )

class Overlays(BaseModel):
    speed: int

    @classmethod
    def from_inprov_overlays(cls, overlays: dict) -> 'Overlays':
        return cls(
            speed = overlays['speed'],
        )

class Service(BaseModel):
    sid: str
    name: str
    type: str
    endpoints: list[Endpoint]
    overlays: Overlays

    @classmethod
    def from_inprov_service(cls, service: dict) -> 'Service':
        return cls(
            sid = service['sid'],
            name = service['name'],
            type = service['type'],
            endpoints = list(map(Endpoint.from_inprov_endpoint, service['endpoints'])),
            overlays = Overlays.from_inprov_overlays(service['overlays']),
        )

class ServiceList(BaseModel):
    services: list[Service]


INPROV_SITE_LIST_SCHEMA = {
    '$schema': 'https://json-schema.org/draft/2020-12/schema',

    'definitions': {
        'site': {
            'type': 'object',
            'properties': {
                'name': {'type': 'string'},
                'latitude': {'type': 'number'},
                'longitude': {'type': 'number'},
            },
            'required': ['name', 'latitude', 'longitude'],
            'additionalProperties': True,
        },
    },

    'type': 'array',
    'items': {'$ref': '#/definitions/site'}
}

INPROV_ROUTER_LIST_SCHEMA = {
    '$schema': 'https://json-schema.org/draft/2020-12/schema',

    'definitions': {
        'router': {
            'type': 'object',
            'properties': {
                'fqdn': {'type': 'string'},
                'site': {'type': 'string'},
            },
            'required': ['fqdn', 'site'],
        },
    },

    'type': 'array',
    'items': {'$ref': '#/definitions/router'}
}

INPROV_SERVICE_LIST_SCHEMA = {
    '$schema': 'https://json-schema.org/draft/2020-12/schema',

    'definitions': {
        'endpoint': {
            'type': 'object',
            'properties': {
                'hostname': {'type': 'string'},
                'interface': {'type': 'string'},
            },
        },
        'service': {
            'type': 'object',
            'properties': {
                'sid': {'type': 'string'},
                'name': {'type': 'string'},
                'type': {'type': 'string'},
                'endpoints': {
                    'type': 'array',
                    'items': {'$ref': '#/definitions/endpoint'},
                    'minItems': 1,
                },
                'overlays': {
                    'type': 'object', 'properties': {
                        'speed': {'type': 'number'},
                    },
                    'required': ['speed'],
                },
            },
            'required': ['sid', 'name', 'type', 'endpoints', 'overlays'],
        },
    },

    'type': 'array',
    'items': {'$ref': '#/definitions/service'}
}

@router.get("/sites")
def get_sites() -> SiteList:
    """
    handler for /sites
    """

    # TODO: catch/handle the usual exceptions

    rv = requests.get(
        'https://test-inprov01.geant.org/map/sites',
        headers={'Accept': 'application/json'})
    rv.raise_for_status()
    site_list_json = rv.json()
    jsonschema.validate(site_list_json, INPROV_SITE_LIST_SCHEMA)

    return SiteList(sites=map(Site.from_inprov_site, site_list_json))


@router.get("/routers")
def get_routers() -> RouterList:
    """
    handler for /sites
    """

    # TODO: catch/handle the usual exceptions

    rv = requests.get(
        'https://test-inprov01.geant.org/map/routers',
        headers={'Accept': 'application/json'})
    rv.raise_for_status()
    router_list_json = rv.json()
    jsonschema.validate(router_list_json, INPROV_ROUTER_LIST_SCHEMA)

    return RouterList(routers=map(Router.from_inprov_router, router_list_json))


@router.get("/trunks")
def get_trunks() -> ServiceList:
    """
    handler for /trunks
    """

    # TODO: catch/handle the usual exceptions

    rv = requests.get(
        'https://test-inprov01.geant.org/map/services/IP TRUNK',
        headers={'Accept': 'application/json'})
    rv.raise_for_status()
    service_list_json = rv.json()
    jsonschema.validate(service_list_json, INPROV_SERVICE_LIST_SCHEMA)

    return ServiceList(services=map(Service.from_inprov_service, service_list_json))