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

import pydash
from adafri.utils.queries import (
    cloud_firestore_query_builder,
    cloud_firestore_query_formatter,
)
from adafri.v1 import version
from adafri.v1.account.models.account import Account
from adafri.v1.files import IMAGES_EXTENSIONS, File
from adafri.v1.files.utils import upload_image_from_url
from adafri.v1.gads.data import DISPLAY_ADS_REQUIREMENTS
from adafri.v1.gads.models.client_customer_id import ClientCustomerId
from firebase_admin.firestore import firestore

from .....utils import (
    ArrayUtils,
    BaseClass,
    DictUtils,
    RequestFields,
    get_object_model_class,
    get_request_fields,
    init_class_kwargs,
    integer,
)
from .....utils.response import ApiResponse, Error, ResponseStatus, StatusCode
from ...models.adgroups.ads.base import BaseAd, BaseAdFieldsProps
from .ad_fields import (
    DISPLAY_ADS_COLLECTION,
    IMAGE_AD_PICKABLE_FIELDS,
    ImageAdFields,
    ImageAdFieldsProps,
)

DISPLAY_ADS_UPLOAD_COLLECTION = "image_upload"

def filter_image_ad_request_fields(fields, default_fields = IMAGE_AD_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 ImageAdToPublish(BaseClass):
    id: str
    name: str
    mediaId: int
    assetId: int
    hash: str
    width: int
    height: int
    urls: str
    url: str
    previewUrl: str
    resourceName: str
    sourceUrl: str
    type: str
    mimeType: str
    referenceId: str
    owner: str
    fileSize: str
    clientCustomerId: str
    def __init__(self, ad=None, **kwargs):
        (cls_object, keys, data_args) = init_class_kwargs(self, ad, None, None, None, [], **kwargs)
        for key in keys:
            if key == ImageAdFields.fileSize:
                if bool(cls_object[key]) is True:
                    setattr(self, key, integer(cls_object[key]))
                else:
                    setattr(self, key, None)
            elif key in [ImageAdFields.mediaId, ImageAdFields.assetId]:
                if bool(cls_object[key]) is True:
                    setattr(self, key, integer(cls_object[key]))
                else:
                    setattr(self, key, None)
            elif key == ImageAdFields.width:
                if bool(cls_object[key]) is True:
                    setattr(self, key, integer(cls_object[key]))
                else:
                    setattr(self, key, None)
            elif key == ImageAdFields.height:
                if bool(cls_object[key]) is True:
                    setattr(self, key, integer(cls_object[key]))
                else:
                    setattr(self, key, None)
            else:
                setattr(self, key, cls_object[key]) 
        if bool(self.urls) and bool(self.url) is False:
            self.url = self.urls
        if bool(self.mediaId) and bool(self.assetId) is False:
            self.assetId = self.mediaId
    def to_dict(self, field=None):
        return DictUtils.remove_none_values({
            "id": self.id,
            "name": self.name,
            "mediaId": self.mediaId,
            "assetId": self.assetId,
            "width": self.width,
            "height": self.height,
            "urls": self.urls,
            "url": self.url,
            "previewUrl": self.previewUrl,
            "resourceName": self.resourceName,
            "sourceUrl": self.sourceUrl,
            "type": self.type,
            "hash": self.hash,
            "mimeType": self.mimeType,
            "owner": self.owner,
            "fileSize": self.fileSize,
            "referenceId": self.referenceId,
            "clientCustomerId": self.clientCustomerId
        })
    @staticmethod
    def from_dict(_obj: Any) -> 'ImageAdToPublish':
        obj = {}
        if bool(_obj) is True:
            if isinstance(_obj, dict):
                obj = _obj.copy()
                if 'urls' in obj and 'url' not in obj:
                    obj['url'] = obj['urls']
                if 'mediaId' in obj and 'assetId' not in obj:
                    obj['assetId'] = obj['mediaId']
            elif isinstance(_obj, ImageAdToPublish):
                obj = _obj.to_dict()
                if 'urls' in obj and 'url' not in obj:
                    obj['url'] = obj['urls']
                if 'mediaId' in obj and 'assetId' not in obj:
                    obj['assetId'] = obj['mediaId']
            elif isinstance(_obj, (str, int)):
                obj = {"id": str(_obj)} 
            else:
                obj = _obj
        cls_object, keys = get_object_model_class(obj, ImageAdToPublish, None);
        return ImageAdToPublish(cls_object)
    
    @staticmethod
    def convert_to_image_ad(value):
        ad = ImageAd();
        if bool(value.urls) is True:
            ad.urls = value.urls
            ad.url_image = value.urls
        if bool(value.name) is True:
            ad.name = value.name
        if bool(value.mediaId) is True:
            ad.mediaId = value.mediaId
            ad.assetId = value.mediaId
        if bool(value.type) is True:
            ad.type = value.type
        if bool(value.width) is True:
            ad.width = value.width
        if bool(value.height) is True:
            ad.height = value.height
        if bool(value.previewUrl) is True:
            ad.previewUrl = value.previewUrl
        if bool(value.sourceUrl) is True:
            ad.sourceUrl = value.sourceUrl
        if bool(value.mimeType) is True:
            ad.mimeType = value.mimeType
        if bool(value.owner) is True:
            ad.owner = value.owner
        if bool(value.fileSize) is True:
            ad.fileSize = value.fileSize
        if bool(value.clientCustomerId) is True:
            ad.clientCustomerId = value.clientCustomerId
        if bool(value.referenceId) is True:
            ad.referenceId = value.referenceId
        return ad
    
    def to_image_ad(self, owner = None):
        if bool(owner) is True:
            self.owner = owner
        return ImageAdToPublish.convert_to_image_ad(self)
@dataclass(init=False)
class ImageAd(BaseAd):
    mediaId: int
    assetId: int
    mimeType: str
    fileSize: int
    hash: str
    previewUrl: str
    referenceId: str | int
    type: str
    sourceUrl: str
    urls: str
    url: str
    url_image: str
    usedForRectangle: bool
    usedForSquare: bool
    width: int
    height: int
    ad_name: str
    ad_type: str
    state: str
    displayUrl: str
    finalAppUrls: list[str]
    finalMobileUrls: list[str]
    finalUrls: list[str]
    google_ads_image_ad: dict
    __baseFields = ImageAdFieldsProps
    class_object = None;
    adgroup: Any | None = None
    customer: ClientCustomerId | None = None
    account: Account | None = None

    def __init__(self, ad=None, **kwargs):
        _ad = ad
        if type(ad) is str:
            _ad = {"id": ad}
        (cls_object, keys, data_args) = init_class_kwargs(self, _ad, IMAGE_AD_PICKABLE_FIELDS, ImageAdFieldsProps, DISPLAY_ADS_COLLECTION, ['id'], **kwargs)
        super().__init__(**{**data_args, "ad": _ad});
        for key in keys:
            if BaseAdFieldsProps.get(key) is None:
                if key == ImageAdFields.account:
                    setattr(self, key, Account.from_dict(cls_object[key]))
                elif key == ImageAdFields.customer:
                    setattr(self, key, ClientCustomerId.from_dict(cls_object[key]))
                elif key == ImageAdFields.adgroup:
                    setattr(self, key, cls_object[key])
                elif key == ImageAdFields.fileSize:
                    setattr(self, key, integer(cls_object[key], None, True))
                else:
                    setattr(self, key, cls_object[key])
        if bool(self.url_image) is False:
            if bool(self.urls) is True:
                self.url_image = self.urls
        self.class_object = ImageAd


    @staticmethod
    def generate_model(_key_="default_value"):
        model = {};
        props = ImageAdFieldsProps
        for k in DictUtils.get_keys(props):
            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'Ad Display {random_suffix}'
        return model;

    @staticmethod
    def from_dict(ad: Any, db=None, collection_name=None) -> 'ImageAd':
        cls_object, keys = get_object_model_class(ad, ImageAd, ImageAdFieldsProps);
        _ad = ImageAd(cls_object, db=db, collection_name=collection_name)
        return _ad
    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 = ImageAd.generate_model()
        model['accountId'] = campaign.accountId
        model['clientCustomerId'] = campaign.clientCustomerId
        if data is not None:
            model = DictUtils.merge_dict(data, model, True)
        # print('create ad with model', model)
        create = ImageAd().create(model, campaign)
        if create.status == 'error':
            return create
        # print('fields', CAMPAIGN_DISPLAY_PICKABLE_FIELDS)
        values = create.data
        # values = DictUtils.omit_fields(values, IMAGE_AD_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 = [ImageAdFields.url_image, 
                ImageAdFields.urls, 
                ImageAdFields.name, 
                ImageAdFields.ad_name, 
                ImageAdFields.ad_type,
                ImageAdFields.displayUrl,
                ImageAdFields.finalUrls,
                ImageAdFields.finalMobileUrls,
                ImageAdFields.finalAppUrls,
                ImageAdFields.fileSize,
                ImageAdFields.width,
                ImageAdFields.referenceId,
                ImageAdFields.mediaId,
                ImageAdFields.assetId,
                ImageAdFields.height]
        return keys
    @staticmethod
    def get_ad_group_props(value):
        if value is None:
            return {}
        return DictUtils.pick_fields(value, ImageAd.property_keys())
    def to_dict(self, fields=None):
        base = super().to_dict(fields)
        return DictUtils.remove_none_values({
            **base,
            "mediaId": self.mediaId,
            "assetId": self.assetId,
            "hash": self.hash,
            "mimeType": self.mimeType,
            "fileSize": self.fileSize,
            "previewUrl": self.previewUrl,
            "referenceId": self.referenceId,
            "type": self.type,
            "sourceUrl": self.sourceUrl,
            "urls": self.urls,
            "url": self.url,
            "url_image": self.url_image,
            "usedForRectangle": self.usedForRectangle,
            "usedForSquare": self.usedForSquare,
            "width": self.width,
            "height": self.height,
            "ad_name": self.ad_name,
            "ad_type": self.ad_type,
            "displayUrl": self.displayUrl,
            "finalAppUrls": self.finalAppUrls,
            "finalMobileUrls": self.finalMobileUrls,
            "finalUrls": self.finalUrls,
            "google_ads_image_ad": self.google_ads_image_ad,
            "customer": self.customer.to_dict().copy() if self.customer is not None else None,
            "account": self.account.to_dict().copy() if self.account is not None else None,
            "adgroup": self.adgroup,
            "state": self.state
    })
    @staticmethod
    def findAd(id, aacid=None):
        print('findAd', id, aacid)
        isID = False
        try:
            id = int(id)
        except Exception as e:
            isID = True
        if isID is True:
            ad = ImageAd.from_dict({"id": id}).get(IMAGE_AD_PICKABLE_FIELDS)
            if ad is None:
                return None
            return ad 
        if id is None or aacid is None or not isinstance(id, int) or not isinstance(aacid, str) or len(aacid) == 0:
            return None
        ad = ImageAd(None).query(ImageAd, "ad", query_params=[{"key": "accountId", "comp": "==", "value": aacid}, {"key": "ad_group_id", "comp": "==", "value": id}], first=True)
        return ad
    def getAds(self, adgroup, fields=['id', 'name'], response_type = 'dict'):
        # print('getAds', fields)
        isID = False
        if adgroup is None:
            return None
        adGroupId = adgroup.id
        try:
            adGroupId = int(adGroupId)
        except:
            isID = True
        if isID is False and adgroup.accountId is None:
            return None
        adgroups = []
        queryParams = [{"key": "accountId", "comp": "==", "value": adgroup.accountId}]
        if isID is False:
            queryParams.append({"key": "ad_group_id", "comp": "==", "value": adGroupId})
        else :
            queryParams.append({"key": "adgroup_id_parent", "comp": "==", "value": adGroupId})
        ads_ = self.query(ImageAd, "ad", query_params=queryParams)
        
        request_fields = filter_image_ad_request_fields(fields)
        for ad in ads_:
            if response_type == 'class':
                adgroups.append(ad)
            else:
                if fields is None:
                    adgroups.append(ad.to_dict())
                    continue
                adgroups.append(DictUtils.filter_by_fields(ad.to_dict(), request_fields))
        return adgroups
    
    def get(self, fields=None):
        if bool(self.id) is None:
            return None;
        request_fields = filter_image_ad_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}
        return ImageAd.from_dict(ad=ImageAd.from_dict(ad=data).to_dict(),  db=self.db, collection_name=self.collection_name);

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

    def getChangedFields(self, data):
        last_value = self.to_dict();
        filtered_value = pydash.pick(data, ImageAdFields().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 generateAd(self, adgroup, data=None, only_generate = False):
        if adgroup is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Adgroup not found","INVALID_REQUEST", 1))

        model = ImageAd.generate_model()
        model['accountId'] = adgroup.accountId
        model['clientCustomerId'] = adgroup.clientCustomerId
        if data is not None:
            model = DictUtils.merge_dict(data, model, True)
        # print('create ad with model', model)
        create = ImageAd().create(model, adgroup, only_generate)
        if create.status == 'error':
            return create
        values = create.data
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, values, None)
    
    def createAssetFile(self):
        file = None
        if bool(self.hash) is False:
            if bool(self.url) is True:
                try:
                    print('checking if file exists', self.url)
                    f = File(collection_name=DISPLAY_ADS_UPLOAD_COLLECTION).query(
                        query_params=cloud_firestore_query_builder(
                        cloud_firestore_query_formatter("file_url", self.url)
                    ), first=True)
                    if f is not None:
                        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, f, None)
                    file = upload_image_from_url(file=self.url, upload_path='', extensions=IMAGES_EXTENSIONS.copy(),accountId=self.accountId, upload_folder=DISPLAY_ADS_UPLOAD_COLLECTION, process=False)
                    if file is not None:
                        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, file, None)
                except Exception as e:
                    print(e)
                    return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot build asset file ref for {self.id} check if {self.url} is a valid image url", "INVALID_REQUEST", 1))
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot build asset file ref for {self.id}", "INVALID_REQUEST", 1))
        file = File({"id": self.hash}, collection_name=DISPLAY_ADS_UPLOAD_COLLECTION).get()
        if file is not None:
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, file, None)
        return ApiResponse(ResponseStatus.OK, StatusCode.status_204, None, None)
    def build_ad_file(self, file: File | None = None, adgroup=None):
        _file = file
        if _file is None and bool(self.hash) is True:
            print('checking if file exists', self.hash)
            _file = File(file={"id": self.hash}, collection_name=DISPLAY_ADS_UPLOAD_COLLECTION).get()
            print('file hash', _file)
        if _file is None:
            asset_create = self.createAssetFile()
            return asset_create
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, _file, None)

    def check_customer_used(self):
        adgroup = self.adgroup
        if adgroup is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Adgroup not found to check ad customer","INVALID_REQUEST", 1))
        
        if self.assetId is not None and self.assetId > 0:
            if self.clientCustomerId != adgroup.clientCustomerId:
                copy = self.to_dict().copy()
                copy['clientCustomerId'] = adgroup.clientCustomerId
                if "id" in copy:
                    del copy["id"]
                if "assetId" in copy:
                    del copy["assetId"]
                copy["name"] = f"Ad copy {uuid.uuid1()}"
                new_ad = ImageAd.from_dict(copy)
                new_ad.adgroup = adgroup
                new_ad.clientCustomerId = adgroup.clientCustomerId
                return ApiResponse(ResponseStatus.OK, StatusCode.status_200, new_ad, None)
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, self, None)
    def check_point_ad(self, file: File | None = None, adgroup: Any | None=None):
        if file is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot find or create asset file to use {self.id}", "INVALID_REQUEST", 1))
        if bool(self.name) is False:
            self.name = f"New Ad upload {uuid.uuid1()}"
        dim_valid = False
        if file.size > 150000:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Invalid ad size {file.size} max 150kb", "INVALID_REQUEST", 1))
        for r in DISPLAY_ADS_REQUIREMENTS.copy():
            if file.width == r['width'] and file.height == r['height']:
                dim_valid = True
                break
        if dim_valid is False:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Invalid ad dimension {self.width}x{self.height}", "INVALID_REQUEST", 1))
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, None, None)
        
    def checkpoint_asset_account(self, act: str | Account | None = None, state: str | None = None):
        error = {"state": state if state is not None else self.state}
        account = self.account;
        id = self.accountId
        if  bool(id) is False:
            if act is not None:
                if isinstance(act, str):
                    id = act
                else:
                    id = act.id
        if bool(id) and (account is None or bool(account) is False or bool(account.id) is False):
            account = Account(id).get()
        if account is not None:
            self.account = account
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, account, None)
        error["message"] = f"Cannot found account for asset {self.id}"
        return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(error, "INVALID_REQUEST", 1))
    def checkpoint_asset_customer(self, customer: str | ClientCustomerId | None = None, state: str | None = None):
        error = {"state": self.state if self.state is not None else state}
        clientCustomer = self.customer
        if clientCustomer is not None:
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, clientCustomer, None)
        id = self.clientCustomerId
        if id is None:
            if customer is not None:
                if isinstance(customer, str):
                    id = customer
                else:
                    id = customer.id
        if clientCustomer is None or bool(clientCustomer) is False or bool(clientCustomer.id) is False:
            if bool(id):
                clientCustomer = ClientCustomerId(id).get()
            else:
                customers = ClientCustomerId().getDefault()
                if bool(customers) is True:
                    clientCustomer = customers[0]
                    self.customer = clientCustomer
                    return ApiResponse(ResponseStatus.OK, StatusCode.status_200, clientCustomer, None)
        if clientCustomer is not None:
            self.customer = clientCustomer
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, clientCustomer, None)
        error["message"] = f"Cannot found customer {id} for asset {self.id}"
        return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(error, "INVALID_REQUEST", 1))
    
    def basic_checkpoint(self) -> 'ApiResponse':
        account_check = self.checkpoint_asset_account()
        if account_check.status == ResponseStatus.ERROR:
            return account_check
        account: Account = account_check.data
        customer_check = self.checkpoint_asset_customer()
        if customer_check.status == ResponseStatus.ERROR:
            return customer_check
        customer: ClientCustomerId = customer_check.data
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, (account, customer), None)

    def build_ad(self, file: File | None = None, fetch=False):
        adgroup = self.adgroup
        if adgroup is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Adgroup not found to check ad customer","INVALID_REQUEST", 1))
        image_copy = ImageAd.from_dict(self.to_dict().copy())
        ad_data = self
        if fetch is True and bool(self.id) is True:
            ad_data = self.get()
        if ad_data is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot find asset {self.id}", "INVALID_REQUEST", 1))
        ad_data.adgroup = image_copy.adgroup 
        base_check = ad_data.basic_checkpoint()
        if base_check.status == ResponseStatus.ERROR:
            return base_check
        account,customer = base_check.data
        ad_data.accountId = account.id
        ad_data.clientCustomerId = customer.id
        ad_data.owner = account.owner
        ad_data.adgroup_id_parent = adgroup.id
        _file = ad_data.build_ad_file(file)
        if _file.status == ResponseStatus.ERROR:
            return _file
        data_file: File = _file.data
        if data_file is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Cannot find asset {self.id}", "INVALID_REQUEST", 1))
        ad_data.url = data_file.file_url
        ad_data.hash = data_file.id
        ad_data.width = data_file.width
        ad_data.height = data_file.height
        ad_data.fileSize = data_file.size
        ad_data.adgroup = adgroup
        ad_data.customer = customer
        ad_data.account = account
        d = ad_data.check_customer_used()
        if d.status == ResponseStatus.ERROR:
            return d
        if isinstance(d.data, ImageAd):
            ad_data = d.data
        check = ad_data.check_point_ad(_file.data, ad_data.adgroup)
        if check.status == ResponseStatus.ERROR:
            return check
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, ad_data, None)
        
    def create(self, data, adgroup, only_generate = False):
        # creation_date = created_at * 1000
        # return DateUtils.from_timestamp(creation_date).isoformat()
        # try:
        # print('campaign account', data)
        self.adgroup = adgroup
        data_create = DictUtils.dict_from_keys(data, ImageAdFields().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({
                "accountId": adgroup.accountId,
                "owner": adgroup.owner,
                "clientCustomerId": adgroup.clientCustomerId,
                "adgroup_id_parent": adgroup.id,
                "createdBy": f"users/{adgroup.owner}"
            }, data_create,True)
        ad = ImageAd.from_dict(data_create)
        ad.adgroup = adgroup
        build = ad.build_ad()
        if build.status == ResponseStatus.ERROR:
            return build
        if isinstance(build.data, ImageAd):
            ad = build.data
        # print('data_create', data_create)
        document_id = self.collection().document().id
        # exist = self.query(ImageAd, "ad", [{"key": "name", "comp": "==", "value": data_create['name']}], True)
        # if exist is not None:
        #     return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(f"Ad name {data_create['name']} already exists","INVALID_REQUEST", 1))
        ad.id = document_id
        create = {**ad.to_dict(), '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);
        ad = ImageAd.from_dict(create).normalize_response()
        if ad is None:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error("Failed to create ad","INVALID_REQUEST", 1))
        return ApiResponse(ResponseStatus.OK, StatusCode.status_200, ad.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):
        try:
            last_value = self.to_dict();
            print('data update', data)
            # print('last', last_value);
            filtered_value = pydash.pick(data, ImageAdFields().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 ad', data_update)
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, data_update, 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));

