import random
import string
from dataclasses import dataclass
from datetime import datetime
from typing import Any

import pydash
from adafri.cache.lib import CacheClass
from adafri.v1 import version
from firebase_admin.firestore import firestore

from .....utils import (
    ArrayUtils,
    BaseClass,
    DictUtils,
    RequestFields,
    get_object_model_class,
    get_request_fields,
    init_class_kwargs,
)
from .....utils.response import ApiResponse, Error, ResponseStatus, StatusCode
from ...data.demographics import ages_data, genders_data
from ...data.devices import devices_data
from ...models.adgroups.base import BaseAdGroup, BaseAdGroupFieldsProps
from ...models.display_ads import DisplayAdsToPublish
from ...models.placement import Website, YoutubeChannel, YoutubeVideo
from ...models.user_interest import UserInterest
from ..ads.native import NativeAdsToPublish
from .adgroup_fields import (
    ADGROUP_DISPLAY_PICKABLE_FIELDS,
    DISPLAY_ADGROUPS_COLLECTION,
    AdGroupDisplayFields,
    AdGroupDisplayFieldsProps,
)


def filter_adgroup_display_request_fields(fields, default_fields = ADGROUP_DISPLAY_PICKABLE_FIELDS):
    request_fields = get_request_fields(fields, default_fields, [default_fields[0]])
    if request_fields is None or bool(request_fields) is False:
        request_fields = [default_fields[0]]
    return request_fields

@dataclass(init=False)
class AdGroupDisplay(BaseAdGroup):
    targetedPlacements: list[Website]
    excludedPlacements: list[Website]
    websites: list[Website]
    youtubeChannels: list[YoutubeChannel]
    youtubeVideos: list[YoutubeVideo]
    user_interest: list[UserInterest]
    __baseFields = AdGroupDisplayFieldsProps
    class_object = None;

    def __init__(self, adgroup=None, **kwargs):
        _adgroup = adgroup
        if type(adgroup) is str:
            _adgroup = {"id": adgroup}
        (cls_object, keys, data_args) = init_class_kwargs(self, _adgroup, ADGROUP_DISPLAY_PICKABLE_FIELDS, AdGroupDisplayFieldsProps, DISPLAY_ADGROUPS_COLLECTION, ['id'], **kwargs)
        super().__init__(**{**data_args, "adgroup": _adgroup});
        for key in keys:
            if BaseAdGroupFieldsProps.get(key) is None:
                website = ['targetedPlacements', 'excludedPlacements', 'websites']
                if key in website:
                    setattr(self, key, Website().fromListDict(cls_object[key]))
                elif key == 'youtubeChannels':
                    setattr(self, key, YoutubeChannel().fromListDict(cls_object[key]))
                elif key == 'youtubeVideos':    
                    setattr(self, key, YoutubeVideo().fromListDict(cls_object[key]))
                elif key == 'images':
                    setattr(self, key, DisplayAdsToPublish().fromListDict(cls_object[key]))
                elif key == 'imagesNative':
                    setattr(self, key, NativeAdsToPublish().fromListDict(cls_object[key]))
                elif key == 'user_interest':
                    setattr(self, key, UserInterest().fromListDict(cls_object[key]))
                else:
                    setattr(self, key, cls_object[key]) 
        self.class_object = AdGroupDisplay
        self.cache = CacheClass("adgroup_display", AdGroupDisplay)

    def placements_to_list(self, devices: list[Website] | None = None, fields = None):
        if devices is None:
            return []
        return Website().toListDict(devices, fields)
    def channels_to_list(self, channels: list[YoutubeChannel] | None = None, fields = None):
        if channels is None:
            return []
        return YoutubeChannel().toListDict(channels, fields)
    def videos_to_list(self, videos: list[YoutubeVideo] | None = None, fields = None):
        if videos is None:
            return []
        return YoutubeVideo().toListDict(videos, fields)
    def interest_to_list(self, interest: list[UserInterest] | None = None, fields = None):
        if interest is None:
            return []
        return UserInterest().toListDict(interest, fields)
    
    def list_to_placements(self, placements: list[Website] | None = None, fields = None):
        if placements is None:
            return []
        return Website().toListDict(placements, fields)
    def list_to_channels(self, channels: list[YoutubeChannel] | None = None, fields = None):
        if channels is None:
            return []
        return YoutubeChannel().toListDict(channels, fields)
    def list_to_videos(self, videos: list[YoutubeVideo] | None = None, fields = None):
        if videos is None:
            return []
        return YoutubeVideo().toListDict(videos, fields)
    def list_to_interests(self, interest: list[UserInterest] | None = None, fields = None):
        if interest is None:
            return []
        return UserInterest().toListDict(interest, fields)
    def is_published(self):
        return self.ad_group_id > 0
    def getChangedFields(self, data):
        last_value = self.to_dict();
        filtered_value = pydash.pick(data, AdGroupDisplayFields().filtered_keys('editable', True));
        new_value = DictUtils.merge_dict(filtered_value, last_value, True);
        _changed_fields = DictUtils.compare_nested_objects(last_value, new_value);
        changed_fields = ArrayUtils.filter(DictUtils.get_keys(_changed_fields), lambda x: str(x).find('.') == -1)
        return changed_fields
    def prepareAddCriterion(self, data):
        adgroup_add: AdGroupDisplay = self.keep_only(AdGroupDisplay.from_dict(data.copy()), pydash.keys(data.copy()));
        data_add = {};
        data_final = {};
        current_websites = self.placements_to_list(self.websites).copy();
        current_channels = self.channels_to_list(self.youtubeChannels).copy();
        current_videos = self.videos_to_list(self.youtubeVideos).copy();
        current_interests = self.interest_to_list(self.user_interest).copy();
        current_ages = self.ages_to_list(self.ages).copy()
        current_genders = self.genders_to_list(self.genders).copy()
        targeted_websites = [];
        targeted_channels = [];
        targeted_videos = []
        targeted_interests = []
        targeted_ages = []
        targeted_genders = []

        valid_campaign_status = ["enabled", "paused"]
        if bool(adgroup_add.name) is True and bool(adgroup_add.name.strip()) is True:
            data_add['name'] = adgroup_add.name;
            data_final['name'] = adgroup_add.name;
        if bool(adgroup_add.status) is True and adgroup_add.status.lower() in valid_campaign_status:
            data_add['status'] = adgroup_add.status;
            data_final['status'] = adgroup_add.status;

        if bool(adgroup_add.ages) is True:
            values_to_add = self.ages_to_list(adgroup_add.ages).copy();
            if bool(current_ages) is True:
                for value in values_to_add:
                    if pydash.find(current_ages, lambda x: x['criterionId']==value['criterionId']) is None:
                        targeted_ages.append(value);
            else:
                for value in values_to_add:
                    targeted_ages.append(value);
        
        if bool(adgroup_add.genders) is True:
            values_to_add = self.genders_to_list(adgroup_add.genders_to_list).copy();
            if bool(current_genders) is True:
                for value in values_to_add:
                    if pydash.find(current_genders, lambda x: x['criterionId']==value['criterionId']) is None:
                        targeted_genders.append(value);
            else:
                for value in values_to_add:
                    targeted_genders.append(value);
        
        if bool(adgroup_add.websites) is True:
            values_to_add = self.placements_to_list(adgroup_add.websites);
            if bool(current_websites) is True:
                for value in values_to_add:
                    if pydash.find(current_websites, lambda x: x['url']==value['url']) is None:
                        targeted_websites.append(value);
            else:
                for value in values_to_add:
                    targeted_websites.append(value);
        
        if bool(adgroup_add.youtubeChannels) is True:
            values_to_add = self.channels_to_list(adgroup_add.youtubeChannels);
            if bool(current_channels) is True:
                for value in values_to_add:
                    if pydash.find(current_channels, lambda x: x['id']==value['id']) is None:
                        targeted_channels.append(value);
            else:
                for value in values_to_add:
                    targeted_channels.append(value);
        
        if bool(adgroup_add.youtubeVideos) is True:
            values_to_add = self.videos_to_list(adgroup_add.youtubeVideos);
            if bool(current_videos) is True:
                for value in values_to_add:
                    if pydash.find(current_videos, lambda x: x['id']==value['id']) is None:
                        targeted_videos.append(value);
            else:
                for value in values_to_add:
                    targeted_videos.append(value);
        
        if bool(adgroup_add.user_interest) is True:
            values_to_add = self.interest_to_list(adgroup_add.user_interest);
            if bool(current_interests) is True:
                for value in values_to_add:
                    if pydash.find(current_interests, lambda x: x['id']==value['id']) is None:
                        targeted_interests.append(value);
            else:
                for value in values_to_add:
                    targeted_interests.append(value);

        if bool(targeted_websites) is True:
            data_add['websites'] = targeted_websites.copy();
            data_final['websites'] = current_websites.copy() + targeted_websites.copy();
            # print('targeted websites', websites)
        if bool(targeted_channels) is True:
            data_add['youtubeChannels'] = targeted_channels.copy();
            data_final['youtubeChannels'] = current_channels.copy() + targeted_channels.copy();
        
        if bool(targeted_videos) is True:
            data_add['youtubeVideos'] = targeted_videos.copy();
            data_final['youtubeVideos'] = current_videos.copy() + targeted_videos.copy();
        
        if bool(targeted_interests) is True:
            data_add['user_interest'] = targeted_interests.copy();
            data_final['user_interest'] = current_interests.copy() + targeted_interests.copy();

        print('data add', data_add)
        if bool(data_add) is False:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_304, None, Error("No data to update","INVALID_REQUEST", 1));
        data_response = {"values": data_add, "combined": data_final};
        return ApiResponse(ResponseStatus.OK, StatusCode.status_304, data_response, None)
    
    def prepareRemoveCriterion(self, data):
        adgroup_remove: AdGroupDisplay = self.keep_only(AdGroupDisplay.from_dict(data.copy()), pydash.keys(data.copy()));
        data_remove = {};
        data_final = {};
        current_websites = self.placements_to_list(self.websites).copy();
        current_channels = self.channels_to_list(self.youtubeChannels).copy();
        current_videos = self.videos_to_list(self.youtubeVideos).copy();
        current_interests = self.interest_to_list(self.user_interest).copy();
        current_ages = self.ages_to_list(self.ages).copy()
        current_genders = self.genders_to_list(self.genders).copy()
        targeted_websites = [];
        targeted_channels = [];
        targeted_videos = []
        targeted_interests = []
        targeted_ages = []
        targeted_genders = []
        if bool(adgroup_remove.websites) is True:
            values_to_remove = self.placements_to_list(adgroup_remove.websites).copy();
            if bool(current_websites) is True:
                for value in values_to_remove:
                    index = pydash.find_index(current_websites, lambda x: x['id']==value['id']);
                    if index != -1:
                        targeted_websites.append(current_websites.copy()[index]);
        if bool(adgroup_remove.youtubeChannels) is True:
            values_to_remove = self.channels_to_list(adgroup_remove.youtubeChannels).copy();
            if bool(current_channels) is True:
                for value in values_to_remove:
                    index = pydash.find_index(current_channels, lambda x: x['id']==value['id']);
                    if index != -1:
                        targeted_channels.append(current_channels.copy()[index]);
        if bool(adgroup_remove.youtubeVideos) is True:
            values_to_remove = self.videos_to_list(adgroup_remove.youtubeVideos).copy();
            if bool(current_videos) is True:
                for value in values_to_remove:
                    index = pydash.find_index(current_videos, lambda x: x['id']==value['id']);
                    if index != -1:
                        targeted_videos.append(current_videos.copy()[index]);
        
        if bool(adgroup_remove.user_interest) is True:
            values_to_remove = self.videos_to_list(adgroup_remove.user_interest).copy();
            if bool(current_interests) is True:
                for value in values_to_remove:
                    index = pydash.find_index(current_interests, lambda x: x['id']==value['id']);
                    if index != -1:
                        targeted_interests.append(current_interests.copy()[index]);
        
        if bool(targeted_websites) is True:
            data_remove['websites'] = targeted_websites.copy();
            data_final['websites'] = ArrayUtils.filter(current_websites, lambda x: pydash.find(targeted_websites, lambda y: x['url']==y['url']) is None);
        if bool(targeted_channels) is True:
            data_remove['youtubeChannels'] = targeted_channels.copy();
            data_final['youtubeChannels'] = ArrayUtils.filter(current_channels, lambda x: pydash.find(targeted_channels, lambda y: x['id']==y['id']) is None);
        if bool(targeted_videos) is True:
            data_remove['youtubeVideos'] = targeted_videos.copy();
            data_final['youtubeVideos'] = ArrayUtils.filter(current_videos, lambda x: pydash.find(targeted_videos, lambda y: x['id']==y['id']) is None);
        if bool(targeted_interests) is True:
            data_remove['user_interest'] = targeted_interests.copy();
            data_final['user_interest'] = ArrayUtils.filter(current_interests, lambda x: pydash.find(targeted_interests, lambda y: x['id']==y['id']) is None);

        data_response = {"values": data_remove, "combined": data_final};
        if bool(data_remove) is False:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_304, None, Error("No data to remove","INVALID_REQUEST", 1));
    
        return ApiResponse(ResponseStatus.OK, StatusCode.status_304, data_response, None);

    @staticmethod
    def generate_model(_key_="default_value"):
        model = {};
        props = AdGroupDisplayFieldsProps
        for k in DictUtils.get_keys(props):
            if k=='ages':
                model[k] = ages_data;
                continue
            if k=='genders':
                model[k] = genders_data;
                continue
            if k=='devicesTargeted':
                model[k] = devices_data;
                continue
            if k=='api_version':
                model[k] = version;
                continue;
            if _key_ in props[k] and props[k][_key_] is not None:
                model[k] = props[k][_key_];
        
        # Generate random campaign name
        random_suffix = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
        model['name'] = f'Campaign Display {random_suffix}'
        model['startDate'] = datetime.now().strftime('%Y-%m-%d')
        return model;

    @staticmethod
    def from_dict(adgroup: Any, db=None, collection_name=None) -> 'AdGroupDisplay':
        cls_object, keys = get_object_model_class(adgroup, AdGroupDisplay, AdGroupDisplayFieldsProps);
        _adgroup = AdGroupDisplay(cls_object, db=db, collection_name=collection_name)
        return _adgroup
    def generateAdgroup(self, campaign, data=None):
        if campaign is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Campaign not found","INVALID_REQUEST", 1))

        model = AdGroupDisplay.generate_model()
        model['accountId'] = campaign.accountId
        model['clientCustomerId'] = campaign.clientCustomerId
        if data is not None:
            model = DictUtils.merge_dict(data, model, True)
        # print('create adgroup with model', model)
        create = AdGroupDisplay().create(model, campaign)
        if create.status == 'error':
            return create
        # print('fields', CAMPAIGN_DISPLAY_PICKABLE_FIELDS)
        values = create.data
        # values = DictUtils.omit_fields(values, ADGROUP_DISPLAY_PICKABLE_FIELDS + ['owner', 'id_campagne', 'ad_group_id'])
        # print('values', values)
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, values, None)
    
    @staticmethod
    def property_keys():
        keys = [AdGroupDisplayFields.ages, 
                AdGroupDisplayFields.genders, 
                AdGroupDisplayFields.devicesTargeted, 
                AdGroupDisplayFields.devicesExcluded, 
                AdGroupDisplayFields.websites,
                AdGroupDisplayFields.youtubeChannels,
                AdGroupDisplayFields.youtubeVideos,
                AdGroupDisplayFields.images,
                AdGroupDisplayFields.imagesNative,
                AdGroupDisplayFields.user_interest]
        return keys
    @staticmethod
    def get_ad_group_props(value):
        if value is None:
            return {}
        return DictUtils.pick_fields(value, AdGroupDisplay.property_keys())
    def to_dict(self, fields=None):
        base = super().to_dict(fields)
        return DictUtils.remove_none_values({
            **base,
            "targetedPlacements": Website().toListDict(self.targetedPlacements, None),
            "excludedPlacements": Website().toListDict(self.excludedPlacements, None),
            "websites": Website().toListDict(self.websites, None),
            "youtubeChannels": YoutubeChannel().toListDict(self.youtubeChannels, None),
            "youtubeVideos": YoutubeVideo().toListDict(self.youtubeVideos, None),
            "images": DisplayAdsToPublish().toListDict(getattr(self, 'images', None), None),
            "imagesNative": NativeAdsToPublish().toListDict(getattr(self, 'imagesNative', None), None),
            "user_interest": UserInterest().toListDict(getattr(self, 'user_interest', None), None),
    })
    @staticmethod
    def findAdgroup(id, aacid=None):
        isID = False
        try:
            id = int(id)
        except Exception as e:
            isID = True
        if isID is True:
            campaign = AdGroupDisplay.from_dict({"id": id}).get(ADGROUP_DISPLAY_PICKABLE_FIELDS)
            if campaign is None:
                return None
            return campaign 
        if id is None or aacid is None or len(id) == 0 or len(aacid) == 0:
            return None
        campaign = AdGroupDisplay(None).query(AdGroupDisplay, "adgroup", query_params=[{"key": "accountId", "comp": "==", "value": aacid}, {"key": "ad_group_id", "comp": "==", "value": id}], first=True)
        print('finding', id)
        return campaign
    def getAdGroups(self, accountId, campaignId, fields=['id', 'name'], response_type = 'dict'):
        isID = False
        try:
            campaignId = int(campaignId)
        except:
            isID = True
        if isID is False and accountId is None:
            return None
        adgroups = []
        queryParams = [{"key": "accountId", "comp": "==", "value": accountId}, ]
        if isID is False:
            queryParams.append({"key": "campaign_id", "comp": "==", "value": campaignId})
        else :
            queryParams.append({"key": "campaign_id_parent", "comp": "==", "value": campaignId})
        adgroups_ = self.query(AdGroupDisplay, "adgroup", query_params=queryParams)
        
        request_fields = filter_adgroup_display_request_fields(fields)
        for adgroup in adgroups_:
            if response_type == 'class':
                adgroups.append(adgroup)
            else:
                if fields is None:
                    adgroups.append(adgroup.to_dict())
                    continue
                adgroups.append(DictUtils.filter_by_fields(adgroup.to_dict(), request_fields))
        return adgroups
    
    def get(self, fields=None):
        if bool(self.id) is None:
            return None;
        adgroup_cache: AdGroupDisplay | None = self.cache.get(self.id);
        if adgroup_cache is not None:
            return adgroup_cache
        request_fields = filter_adgroup_display_request_fields(fields)
        doc = self.document_reference().get();
        if doc.exists is False:
            return None;
        doc_dict = doc.to_dict()
        if 'id' in doc_dict and bool(doc_dict['id']) is False:
            del doc_dict['id']
        data = {"id": doc.id, **doc_dict}
        adgroup = AdGroupDisplay.from_dict(adgroup=AdGroupDisplay.from_dict(adgroup=data).to_dict(),  db=self.db, collection_name=self.collection_name)
        self.cache.set(adgroup.id, adgroup);
        return adgroup;

    def getByUserId(self,id, fields=None):
        adgroups = [];
        request_fields = filter_adgroup_display_request_fields(fields)
        docs = self.collection().where('owner','==',id).get();
        for doc in docs:
            data = doc.to_dict();
            data['id'] = doc.id;
            adgroups.append(AdGroupDisplay.from_dict(adgroup=AdGroupDisplay.from_dict(adgroup=data).to_json(request_fields),  db=self.db, collection_name=self.collection_name));
        return adgroups;
    def normalize_response(self):
        data = AdGroupDisplay.from_dict(DictUtils.pick_fields(self.to_dict(), ADGROUP_DISPLAY_PICKABLE_FIELDS))
        return AdGroupDisplay.from_dict(DictUtils.omit_fields(data.to_dict(), ["owner", "createdBy"]))

    def create(self, data, campaign, only_generate = False):
        # creation_date = created_at * 1000
        # return DateUtils.from_timestamp(creation_date).isoformat()
        # try:
        # print('campaign account', data)
        data_create = DictUtils.dict_from_keys(data, AdGroupDisplayFields().filtered_keys('mutable', True));
        if bool(data_create) is False:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Invalid request","INVALID_REQUEST", 1))
        data_create = DictUtils.merge_dict({
                "provider": campaign.provider,
                "accountId": campaign.accountId,
                "owner": campaign.owner,
                "clientCustomerId": campaign.clientCustomerId,
                "campaign_id_parent": campaign.id,
                "createdBy": f"users/{campaign.owner}"
            }, data_create,True)
        # print('data_create', data_create)
        document_id = self.collection().document().id
        query_filter = [{"key": "name", "comp": "==", "value": data_create['name']}, {"key": "accountId", "comp": "==", "value": campaign.accountId}, {"key": "clientCustomerId", "comp": "==", "value": campaign.clientCustomerId}];
        exist = self.query(AdGroupDisplay, "adgroup", query_filter, True)
        if exist is not None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, exist, Error(f"Adgroup name {data_create['name']} already exists","DUPLICATE_ENTITY", 2))
        model = AdGroupDisplay.generate_model()
        model['id'] = document_id
        data_create = DictUtils.merge_dict(data_create, model, True)
        create = {**data_create, 'createdAt': firestore.SERVER_TIMESTAMP}
        if only_generate is False or only_generate is None:
            doc_ref = self.collection().document(document_id);
            doc_ref.set(create, True);
        adgroup = AdGroupDisplay.from_dict(create).normalize_response()
        if adgroup is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Failed to create adgroup","INVALID_REQUEST", 1))
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, adgroup.normalize_response(), None);  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the created campaign object.  # Return the
        # except Exception as e:
        #     print(e)
        #     return {"error": "Exception creating campaign"};

    def update(self, data, silent = True):
        try:
            data_update = {};
            changed_fields = [];
            if silent is True:
                data_update = pydash.pick(data, AdGroupDisplayFields().filtered_keys('pickable', True));
            else:
                last_value = self.to_dict();
                print('data update', data)
                # print('last', last_value);
                filtered_value = pydash.pick(data, AdGroupDisplayFields().filtered_keys('editable', True));
                # print('filtered', filtered_value);
                new_value = DictUtils.merge_dict(filtered_value, last_value, True);
                _changed_fields = DictUtils.compare_nested_objects(last_value, new_value);
                changed_fields = ArrayUtils.filter(DictUtils.get_keys(_changed_fields), lambda x: str(x).find('.') == -1)
                data_update = DictUtils.dict_from_keys(filtered_value, changed_fields);
            if bool(data_update) is False:
                return ApiResponse(ResponseStatus.OK, StatusCode.status_200, data_update, None);
            # try:
            #     self.document_reference().set(data_update, merge=True)
            # except Exception as e:
            #     return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(str(e),"INVALID_REQUEST", 1))
            # return DictUtils.dict_from_keys(self.get(), changed_fields);
            # fields = changed_fields
            print('data_update adgroup', data_update)
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, DictUtils.pick_fields(data_update, ADGROUP_DISPLAY_PICKABLE_FIELDS), None);
        except Exception as e:
            print(e)
            return None;

    def to_json(self, _fields=None):
        return self.to_dict()
    def remove(self, only_mark_as_removed=True):
        if self.is_removed is True:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_500, None, Error(f"Adgroup {self.id} already removed","INVALID_REQUEST", 1));
        try:
            if self.id is None:
                return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot identify Campaign with id {self.id}","INVALID_REQUEST", 1));
            if only_mark_as_removed:
                self.document_reference().set({"is_removed": True}, merge=True)
            else:
                self.document_reference().delete();
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, {"message": f"Campaign {self.id} deleted"}, None);
        except:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"An error occurated while removing authorization code with id {self.id}","INVALID_REQUEST", 1));

