import uuid
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Any, Optional

from adafri.v1.base.firebase_collection import FirebaseCollectionBase

MESSAGE_COLLECTION = 'workflow_channel_messages'

MESSAGE_PICKABLE_FIELDS = [
    'id', 'channelId', 'workspaceId', 'authorUid', 'authorName',
    'content', 'threadParentId', 'reactions', 'isEdited', 'editedAt', 'createdAt',
]

MESSAGE_MUTABLE_FIELDS = ['content', 'reactions', 'isEdited', 'editedAt']


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _new_id() -> str:
    return str(uuid.uuid4())


@dataclass(init=False)
class WorkflowChannelMessage(FirebaseCollectionBase):
    id: str
    channelId: str
    workspaceId: str
    authorUid: str
    authorName: str
    content: str
    threadParentId: Optional[str]
    reactions: dict
    isEdited: bool
    editedAt: Optional[str]
    createdAt: str

    def __init__(self, data=None, **kwargs):
        super().__init__(collection_name=MESSAGE_COLLECTION, **kwargs)
        d = data or {}
        self.id = d.get('id') or _new_id()
        self.channelId = d.get('channelId', '')
        self.workspaceId = d.get('workspaceId', '')
        self.authorUid = d.get('authorUid', '')
        self.authorName = d.get('authorName', '')
        self.content = d.get('content', '')
        self.threadParentId = d.get('threadParentId')
        self.reactions = dict(d.get('reactions') or {})
        self.isEdited = bool(d.get('isEdited', False))
        self.editedAt = d.get('editedAt')
        self.createdAt = d.get('createdAt') or _now()

    @classmethod
    def from_dict(cls, obj: Any, **kwargs) -> 'WorkflowChannelMessage':
        return cls(obj, **kwargs)

    def to_dict(self) -> dict:
        return {
            'id': self.id,
            'channelId': self.channelId,
            'workspaceId': self.workspaceId,
            'authorUid': self.authorUid,
            'authorName': self.authorName,
            'content': self.content,
            'threadParentId': self.threadParentId,
            'reactions': self.reactions,
            'isEdited': self.isEdited,
            'editedAt': self.editedAt,
            'createdAt': self.createdAt,
        }

    @staticmethod
    def toListDict(items: list, fields=None) -> list:
        return [item.to_dict() for item in items]

    @classmethod
    def find(cls, message_id: str) -> 'Optional[WorkflowChannelMessage]':
        inst = cls()
        doc = inst.collection().document(message_id).get()
        if not doc.exists:
            return None
        return cls({**doc.to_dict(), 'id': doc.id})

    @classmethod
    def listByChannel(
        cls, channel_id: str, since: Optional[str] = None
    ) -> 'list[WorkflowChannelMessage]':
        inst = cls()
        query = (
            inst.collection()
            .where('channelId', '==', channel_id)
            .where('threadParentId', '==', None)
            .order_by('createdAt')
        )
        if since:
            query = query.where('createdAt', '>', since)
        docs = query.stream()
        return [cls({**d.to_dict(), 'id': d.id}) for d in docs]

    @classmethod
    def listThread(cls, parent_id: str) -> 'list[WorkflowChannelMessage]':
        inst = cls()
        docs = (
            inst.collection()
            .where('threadParentId', '==', parent_id)
            .order_by('createdAt')
            .stream()
        )
        return [cls({**d.to_dict(), 'id': d.id}) for d in docs]

    def save(self) -> 'WorkflowChannelMessage':
        self.collection().document(self.id).set(self.to_dict())
        return self

    def update(self, data: dict) -> 'WorkflowChannelMessage':
        filtered = {k: v for k, v in data.items() if k in MESSAGE_MUTABLE_FIELDS}
        self.collection().document(self.id).update(filtered)
        for k, v in filtered.items():
            setattr(self, k, v)
        return self

    def delete(self) -> None:
        self.collection().document(self.id).delete()
