import hashlib
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Any

from .....utils import DictUtils, Crypto, get_object_model_class, init_class_kwargs
from ....base.firebase_collection import FirebaseCollectionBase, getTimestamp
from .mfa_fields import MFAFields, MFAFieldsProps, STANDARD_FIELDS, MFA_COLLECTION
from .....utils.response import ApiResponse, Error, ResponseStatus, StatusCode


@dataclass(init=False)
class MFACredential(FirebaseCollectionBase):
    id: str
    user_uid: str
    method: str
    totp_secret: str
    phone: str
    backup_codes: list
    is_enabled: bool
    enrolled_at: str
    last_used_at: str

    def __init__(self, mfa=None, **kwargs):
        if type(mfa) is str:
            mfa = {"user_uid": mfa}
        (cls_object, keys, data_args) = init_class_kwargs(self, mfa, STANDARD_FIELDS, MFAFieldsProps, MFA_COLLECTION, ['id'], **kwargs)
        super().__init__(**data_args)
        for key in keys:
            setattr(self, key, cls_object[key])

    @staticmethod
    def generate_model(_key_="default_value"):
        model = {}
        props = MFAFieldsProps
        for k in DictUtils.get_keys(props):
            model[k] = props[k][_key_]
        return model

    @staticmethod
    def from_dict(mfa: Any = None, db=None, collection_name=None) -> 'MFACredential':
        cls_object, keys = get_object_model_class(mfa, MFACredential, MFAFieldsProps)
        return MFACredential(cls_object, db=db, collection_name=collection_name)

    def query(self, query_params: list, first=False, limit=None):
        try:
            result = []
            query_result = self.custom_query(query_params, first=first, limit=limit)
            if bool(query_result):
                if first:
                    return MFACredential.from_dict(mfa=query_result, db=self.db, collection_name=self.collection_name)
                else:
                    for doc in query_result:
                        result.append(MFACredential.from_dict(mfa=doc, db=self.db, collection_name=self.collection_name))
                    return result
            return None if first else []
        except Exception as e:
            print('Exception while querying MFACredential', e)
            return None if first else []

    def to_dict(self):
        return {
            "id": self.id,
            "user_uid": self.user_uid,
            "method": self.method,
            "totp_secret": self.totp_secret,
            "phone": self.phone,
            "backup_codes": self.backup_codes,
            "is_enabled": self.is_enabled,
            "enrolled_at": self.enrolled_at,
            "last_used_at": self.last_used_at,
        }

    def to_json(self, _fields=None):
        return self.to_dict()

    def get_by_user(self, uid: str) -> 'MFACredential':
        return self.query([{"key": MFAFields.user_uid, "comp": "==", "value": uid}], first=True)

    def create(self, **kwargs):
        model = DictUtils.merge_dict(kwargs, self.generate_model())
        obj = MFACredential.from_dict(model)
        obj.id = Crypto().generate_id(obj.user_uid + "~mfa")
        obj.enrolled_at = datetime.now(timezone.utc).isoformat()
        doc_ref = MFACredential(obj.to_json()).document_reference()
        doc_ref.set({**obj.to_json(), "createdAt": getTimestamp()}, merge=True)
        return obj

    def update(self, data: dict):
        try:
            doc_ref = self.document_reference()
            doc_ref.set(data, merge=True)
            return data
        except Exception as e:
            print('Exception while updating MFACredential', e)
            return None

    def remove(self):
        try:
            self.document_reference().delete()
            return ApiResponse(ResponseStatus.OK, StatusCode.status_200, {"message": f"MFA {self.id} deleted"}, None)
        except Exception as e:
            return ApiResponse(ResponseStatus.ERROR, StatusCode.status_400, None, Error(str(e), "INVALID_REQUEST", 1))
