import datetime
from logging.config import dictConfig
import logging
from uuid import UUID

from fastapi import FastAPI, Header, Request, Response
from pydantic import BaseModel
import pynetbox
from starlette.middleware.cors import CORSMiddleware

# from osism.tasks import netbox
from osism import settings


class WebhookNetboxResponse(BaseModel):
    result: str


class WebhookNetboxData(BaseModel):
    username: str
    data: dict
    snapshots: dict
    event: str
    timestamp: datetime.datetime
    model: str
    request_id: UUID


# https://stackoverflow.com/questions/63510041/adding-python-logging-to-fastapi-endpoints-hosted-on-docker-doesnt-display-api
class LogConfig(BaseModel):
    """Logging configuration to be set for the server"""

    LOGGER_NAME: str = "mycoolapp"
    LOG_FORMAT: str = "%(levelprefix)s | %(asctime)s | %(message)s"
    LOG_LEVEL: str = "DEBUG"

    # Logging config
    version = 1
    disable_existing_loggers = False
    formatters = {
        "default": {
            "()": "uvicorn.logging.DefaultFormatter",
            "fmt": LOG_FORMAT,
            "datefmt": "%Y-%m-%d %H:%M:%S",
        },
    }
    handlers = {
        "default": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
        },
    }
    loggers = {
        "api": {"handlers": ["default"], "level": LOG_LEVEL},
    }


app = FastAPI()

app.add_middleware(
    CORSMiddleware
)

dictConfig(LogConfig().dict())
logger = logging.getLogger("api")

nb = None


@app.on_event("startup")
async def startup_event():
    global nb

    nb = pynetbox.api(
        settings.NETBOX_URL,
        token=settings.NETBOX_TOKEN
    )

    if settings.IGNORE_SSL_ERRORS:
        import requests
        requests.packages.urllib3.disable_warnings()
        session = requests.Session()
        session.verify = False
        nb.http_session = session


@app.get("/")
async def root():
    return {"message": "Hello World"}


@app.post("/webhook/netbox", response_model=WebhookNetboxResponse, status_code=200)
async def webhook(
    webhook_input: WebhookNetboxData,
    request: Request,
    response: Response,
    content_length: int = Header(...),
    x_hook_signature: str = Header(None)
):
    global nb

    data = webhook_input.data
    url = data['url']
    name = data['name']

    if 'devices' in url:
        tags = [x['name'] for x in data['tags']]

        custom_fields = data['custom_fields']
        device_type = custom_fields['device_type']

        # NOTE: device without a defined device_type are nodes
        if not device_type:
            device_type = "node"

    elif 'interfaces' in url:
        device_type = "interface"

        device_id = data['device']['id']
        device = nb.dcim.devices.get(id=device_id)
        tags = [str(x) for x in device.tags]
        custom_fields = device.custom_fields

    if "Managed by OSISM" in tags:
        if device_type == "switch":
            logger.info(f"Handling change for managed device {name} of type {device_type}")
            # netbox.generate.delay(name, custom_fields['configuration_template'])
        elif device_type == "interface":
            logger.info(f"Handling change for interface {name} on managed device {device.name} of type {custom_fields['device_type']}")
            # netbox.generate.delay(device.name, custom_fields['configuration_template'])

    else:
        logger.info(f"Ignoring change for unmanaged device {name}")

    return {"result": "ok"}
