# -*- coding: utf-8 -*-
import re

from datetime import datetime, date
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render
from django.urls import reverse
from ninja import NinjaAPI
from ninja.errors import ValidationError as NinjaValidationError
from ninja.openapi import urls
from ninja.responses import NinjaJSONEncoder
from pydantic import BaseModel

from events.v3.errors import ValidationError as ApiValidationError
from events.v3.routers.surveys import router as surveys_router
from events.v3.routers.surveygroups import router as surveygroups_router
from events.v3.routers.users import router as users_router
from events.v3.routers.notifications import router as notifications_router
from events.v3.routers.operations import router as operations_router
from events.v3.routers.suggests import router as suggests_router
from events.v3.routers.followers import router as followers_router


def patched_json_encoder(self, o):
    if isinstance(o, set):
        return tuple(o)
    elif isinstance(o, (datetime, date)):
        return o.isoformat()
    elif isinstance(o, BaseModel):
        return o.dict()
    return super().default(o)


NinjaJSONEncoder.default = patched_json_encoder
api = NinjaAPI(version='3')
api.add_router('/surveys/', surveys_router)
api.add_router('/survey-groups/', surveygroups_router)
api.add_router('/users/', users_router)
api.add_router('/notifications/', notifications_router)
api.add_router('/operations/', operations_router)
api.add_router('/suggests/', suggests_router)
api.add_router('/followers/', followers_router)


def swagger_redoc(request, api):
    context = {
        'api': api,
        'openapi_json_url': reverse(f'{api.urls_namespace}:openapi-json'),
    }
    return render(request, 'ninja/redoc.html', context)


urls.swagger = swagger_redoc


@api.exception_handler(ObjectDoesNotExist)
def object_does_not_exist(request, exc):
    return api.create_response(request, {'detail': 'Not found'}, status=404)


def get_converted_error(error):
    new_error = {
        'error_code': error['type'],
        'msg': error['msg'],
    }
    loc = []
    skip = True
    for part in error['loc']:
        # в ответе отдаем только значащие поля, служебные убираем
        if skip and re.match(r'^(body|data|__root__|[A-Z]\w+In)$', part):
            continue
        skip = False
        loc.append(part)
    new_error['loc'] = loc
    return new_error


@api.exception_handler(NinjaValidationError)
def ninja_validation_error(request, exc):
    response = [get_converted_error(error) for error in exc.errors]
    return api.create_response(request, response, status=400)


@api.exception_handler(ApiValidationError)
def api_validation_error(request, exc):
    response = [error.dict() for error in exc.errors]
    return api.create_response(request, response, status=400)
