from typing import List, Optional
from pymongo.database import Database
from pymongo.collection import Collection
from bson import ObjectId, errors as bson_errors
from app.models.entities import SubjectEntity


class SubjectRepository:
    COLLECTION_NAME = "subjects"

    def __init__(self, db: Database):
        self.collection: Collection = db[self.COLLECTION_NAME]

    def create(self, subject: SubjectEntity) -> str:
        subject_dict = subject.model_dump(by_alias=True, exclude_none=True)
        result = self.collection.insert_one(subject_dict)
        return str(result.inserted_id)

    def get_all(self) -> List[SubjectEntity]:
        return [SubjectEntity(**doc) for doc in self.collection.find()]

    def get_by_id(self, subject_id: str) -> Optional[SubjectEntity]:
        try:
            oid = ObjectId(subject_id)
        except bson_errors.InvalidId:
            return None

        doc = self.collection.find_one({"_id": oid})
        return SubjectEntity(**doc) if doc else None

    def get_by_ids(self, subject_ids: List[str]) -> List[SubjectEntity]:
        object_ids = []
        for sid in subject_ids:
            try:
                object_ids.append(ObjectId(sid))
            except bson_errors.InvalidId:
                continue

        if not object_ids:
            return []

        cursor = self.collection.find({"_id": {"$in": object_ids}})
        return [SubjectEntity(**doc) for doc in cursor]

    def update(self, subject_id: str, update_data: dict) -> bool:
        try:
            oid = ObjectId(subject_id)
        except bson_errors.InvalidId:
            return False

        result = self.collection.update_one({"_id": oid}, {"$set": update_data})
        return result.modified_count > 0

    def delete(self, subject_id: str) -> bool:
        try:
            oid = ObjectId(subject_id)
        except bson_errors.InvalidId:
            return False

        result = self.collection.delete_one({"_id": oid})
        return result.deleted_count > 0
