from functools import reduce
import traceback

from rest_framework import status
from rest_framework.exceptions import ErrorDetail
from rest_framework.response import Response
from rest_framework.views import exception_handler

from fwd_api.exception.exceptions import GeneralException
from django.utils.translation import gettext as _


def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc, context)

    # Now add the HTTP status code to the response.
    traceback.print_exc()

    if hasattr(exc, 'excArgs'):
        excArgs = exc.excArgs
        if 'detail' not in response.data:
            raise GeneralException()
        detail_error: ErrorDetail = response.data['detail']

        if not hasattr(detail_error, 'code'):
            setattr(detail_error, 'code', '9999')
        if isinstance(excArgs, str):
            response.data = {'code': detail_error.code, 'detail': _(detail_error).format(_(excArgs)),
                             'invalid_fields': [excArgs]}
            return response
        if isinstance(excArgs, tuple):
            translated_args = tuple(map(lambda arg: _(arg), excArgs))
            response.data = {
                'code': detail_error.code,
                'detail': _(detail_error).format(*translated_args)
            }
            return response
        if isinstance(excArgs, list):
            excArgs = list(excArgs)
            response.data = {'code': detail_error.code,
                             'detail': _(detail_error).format(reduce((lambda x, y: _(x) + " , " + _(y)), excArgs)),
                             'invalid_fields': excArgs}
            return response
        response.data = {'code': detail_error.code, **response.data}
        return response
    if exc and not response:
        res = Response()
        res.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
        res.data = {'code': '9999', 'detail': "Internal Error"}
        return res
    return response
