from datetime import datetime, timezone

from core.config import get_db
from core.security.exceptions import CoreDBError, GenericError
from models.course_allocation import CourseAllocation
from schema.course_allocation import CourseAllocationResponse


class CourseAllocationService:

    def save(self, request):
        with get_db() as db:
            payload = request.model_dump()
            try:
                new_course_allocation = CourseAllocation(**payload)
                db.add(new_course_allocation)
                db.commit()
                db.refresh(new_course_allocation)
                return new_course_allocation
            except Exception as e:
                db.rollback()
                raise CoreDBError(f"Could not create new course allocation: {e}")

    def fetch_all_course_allocation(self):
        with get_db() as db:
            records = db.query(CourseAllocation).where(CourseAllocation.deleted_at.is_(None)).all()
            return [CourseAllocationResponse.model_validate(record).model_dump() for record in records]

    def course_allocation_detail(self, course_allocation_id: int):
        with get_db() as db:
            record = db.query(CourseAllocation).where(
                CourseAllocation.id == course_allocation_id,
                CourseAllocation.deleted_at.is_(None)
            ).first()

            if not record:
                raise GenericError(status_code=404, exc="Course allocation not found")
            return CourseAllocationResponse.model_validate(record).model_dump()

    def update_course_allocation(self, course_allocation_id, request):
        payload = request.model_dump(exclude=['id'])
        with get_db() as db:
            result = (
                db.query(CourseAllocation)
                .filter(CourseAllocation.id == course_allocation_id, CourseAllocation.deleted_at.is_(None))
                .update(payload, synchronize_session="fetch")
            )
            db.commit()
            if result == 0:
                raise GenericError(status_code=422, exc="Could not update course allocation")

    def delete_course_allocation(self, course_allocation_id):
        with get_db() as db:
            course_allocation = db.query(CourseAllocation).where(
                CourseAllocation.id == course_allocation_id,
                CourseAllocation.deleted_at.is_(None)
            ).first()

            if not course_allocation:
                raise GenericError(status_code=404, exc="Course allocation not found")

            course_allocation.deleted_at = datetime.now(timezone.utc)
            db.commit()
            return {"message": "Course allocation deleted successfully"}

    def filter_allocation_by_course_id(self, course_id):
        with get_db() as db:
            records = db.query(CourseAllocation).filter(CourseAllocation.deleted_at.is_(None),
                                                        CourseAllocation.course_id == course_id).all()
            return [CourseAllocationResponse.model_validate(record).model_dump() for record in records]
