# -*- coding: utf-8 -*-
# @Author  : YY

import functools
from typing import Any, Callable
from flask import Response, make_response
from werkzeug.exceptions import HTTPException, InternalServerError

from ruoyi_common.base.model import BaseEntity,VoSerializerContext
from ruoyi_common.base.signal import log_signal
from ruoyi_common.exception import ServiceException
from ruoyi_common.utils.base import DescriptUtil


class BaseSerializer:
    
    def __call__(self, func) -> Callable:
        
        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            try:
                res = func(*args, **kwargs)
            except HTTPException as e:
                # self.send_http_exception(func, e)
                raise e
            except Exception as e:
                raise e
            else:
                response = self.serialize(func, res)
                self.send_success(func, res)
            return response
        return wrapper

    def send_http_exception(self, func, e:HTTPException):
        """
        发送http异常的消息
        
        Args:
            func: 被装饰的函数
            e: http异常
        """
        raw_func = DescriptUtil.get_raw(func)
        log_signal.send(raw_func,message=e)
        
    def send_success(self, func, res:Response):
        """
        发送成功响应的消息
        
        Args:
            func: 被装饰的函数
            res: 成功响应
        """
        raw_func = DescriptUtil.get_raw(func)        
        log_signal.send(raw_func,message=res)
    
    def serialize(self, func, res:Any) -> Response:
        """
        序列化对象
        
        Args:
            func: 被装饰的函数
            res: 被序列化的对象
        
        Returns:
            Response: 序列化后的Response对象
        """
        if isinstance(res, Response):
            response = res
        else:
            response = make_response(res, 200)
        return response

    
class JsonSerializer(BaseSerializer):
    
    def __init__(self, 
        exclude_fields: list=[], 
        include_fields: list|None=None, 
        exclude_none: bool=False, 
        exclude_unset: bool=False, 
        exclude_default: bool=False,
        success_code: int=200, 
        mimetype: str='application/json', 
        headers: dict={},
        ):

        self.mimetype = mimetype
        self.headers = headers
        self.success_code = success_code
        self.context = VoSerializerContext(
            by_alias=True,
            exclude_fields=exclude_fields,
            include_fields=include_fields,
            exclude_none=exclude_none,
            exclude_unset=exclude_unset,
            exclude_default=exclude_default
        )

    def serialize(self, func, res:Any) -> Response:
        """
        序列化对象
        
        Args:
            func: 被装饰的函数
            res: 被序列化的对象
        
        Returns:
            Response: 序列化后的Response对象
        """
        if isinstance(res, BaseEntity):
            response = self.handle_entity(func, res)
        elif isinstance(res, list) and len(res) == 2:
            res, code = res
            response = self.serialize(func,res)
            response.status_code = code
        elif isinstance(res, Response):
            response = res
        else:
            response = self.handle_other(func, res)
        return response
    
    def handle_entity(self, func, res:BaseEntity) -> Response:
        """
        处理BaseEntity对象
        
        Args:
            func: 被装饰的函数
            res: 被序列化的对象
        
        Returns:
            Response: 序列化后的Response对象
        """
        try:
            res = res.model_dump_json(
                **self.context.as_kwargs(),
                context=self.context
            )
        except HTTPException as e:
            http_exc = InternalServerError(description="序列化实体对象异常")
            self.send_http_exception(func, http_exc)
            raise http_exc
        except Exception as e:
            raise e
        else:
            response = make_response(res, self.success_code)
            if self.mimetype:
                response.mimetype = self.mimetype
            if self.headers:
                response.headers.update(self.headers)
        return response
    
    def handle_other(self, func, res:Any) -> Response:
        """
        处理其他对象
        
        Args:
            func: 被装饰的函数
            res: 被序列化的对象
        
        Returns:
            Response: 序列化后的Response对象
        """
        try:
            response = make_response(res)
            if self.mimetype:
                response.mimetype = self.mimetype
            if self.headers:
                response.headers.update(self.headers)
        except HTTPException as e:
            http_exc = InternalServerError(description="序列化其他对象异常")
            self.send_http_exception(func, http_exc)
            raise http_exc
        except Exception as e:
            raise e
        return response
