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

from adafri.v1.base.firebase_collection import FirebaseCollectionBase

MEMBER_COLLECTION = 'workflow_members'

MEMBER_PICKABLE_FIELDS = [
    'id', 'workspaceId', 'uid', 'email', 'displayName',
    'role', 'teamIds', 'status', 'joinedAt',
]

MEMBER_MUTABLE_FIELDS = ['role', 'displayName', 'teamIds', 'status']

MEMBER_ROLES = ['owner', 'admin', 'editor', 'viewer', 'guest']


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


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


class WorkflowMemberFields:
    @staticmethod
    def check_invite_fields(data: dict) -> dict:
        if not data:
            return {'error': 'Missing data'}
        if not data.get('workspaceId', '').strip():
            return {'error': 'workspaceId is required'}
        if not data.get('email', '').strip():
            return {'error': 'email is required'}
        role = data.get('role', 'viewer')
        if role not in MEMBER_ROLES:
            return {'error': f"role must be one of: {', '.join(MEMBER_ROLES)}"}
        return data

    @staticmethod
    def mutable_keys() -> list:
        return MEMBER_MUTABLE_FIELDS


@dataclass(init=False)
class WorkflowMember(FirebaseCollectionBase):
    id: str
    workspaceId: str
    uid: str
    email: str
    displayName: str
    role: str
    teamIds: list
    status: str
    joinedAt: str

    def __init__(self, data=None, **kwargs):
        super().__init__(collection_name=MEMBER_COLLECTION, **kwargs)
        d = data or {}
        self.id = d.get('id') or _new_id()
        self.workspaceId = d.get('workspaceId', '')
        self.uid = d.get('uid', '')
        self.email = d.get('email', '')
        self.displayName = d.get('displayName', '')
        self.role = d.get('role', 'viewer')
        self.teamIds = list(d.get('teamIds') or [])
        self.status = d.get('status', 'active')
        self.joinedAt = d.get('joinedAt') or _now()

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

    def to_dict(self) -> dict:
        return {
            'id': self.id,
            'workspaceId': self.workspaceId,
            'uid': self.uid,
            'email': self.email,
            'displayName': self.displayName,
            'role': self.role,
            'teamIds': self.teamIds,
            'status': self.status,
            'joinedAt': self.joinedAt,
        }

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

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

    @classmethod
    def findByUid(cls, workspace_id: str, uid: str) -> 'Optional[WorkflowMember]':
        inst = cls()
        docs = (
            inst.collection()
            .where('workspaceId', '==', workspace_id)
            .where('uid', '==', uid)
            .limit(1)
            .stream()
        )
        for d in docs:
            return cls({**d.to_dict(), 'id': d.id})
        return None

    @classmethod
    def listByWorkspace(cls, workspace_id: str) -> 'list[WorkflowMember]':
        inst = cls()
        docs = (
            inst.collection()
            .where('workspaceId', '==', workspace_id)
            .order_by('joinedAt')
            .stream()
        )
        return [cls({**d.to_dict(), 'id': d.id}) for d in docs]

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

    def updateRole(self, role: str) -> 'WorkflowMember':
        if role not in MEMBER_ROLES:
            raise ValueError(f"Invalid role: {role}")
        self.collection().document(self.id).update({'role': role})
        self.role = role
        return self

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