import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import List, Optional

from sqlalchemy.orm import joinedload
from sqlalchemy import and_

from core.config import get_db, BASE_PATH
from core.security.exceptions import GenericError
from models.bursary_class import BursaryClassForm, BursaryClassFormDetails
from schema.bursary_class_form import BursaryClassFormResponseSchema, BursaryClassFormDetailsSchema


class BursaryClassService:

    async def upload_file(self, file):
        """Upload file and return filename"""
        if file:
            file_extension = Path(file.filename).suffix
            new_filename = f"{uuid.uuid4()}{file_extension}"
            file_location = BASE_PATH / f'uploads/{new_filename}'
            content = await file.read()
            with open(file_location, "wb") as f:
                f.write(content)
            return new_filename
        return None

    async def create_bursary_class_form(
        self,
        parent_id: int,
        parent_primary_contact: str,
        parent_secondary_contact: Optional[str] = None,
        parent_email: Optional[str] = None,
        file=None,
        participant_info: List[dict] = None
    ):
        """Create bursary class form with nested participant info"""
        try:
            # Upload file if provided
            file_name = await self.upload_file(file)

            with get_db() as db:
                # Create bursary class form
                bursary_class = BursaryClassForm(
                    parent_id=parent_id,
                    parent_primary_contact=parent_primary_contact,
                    parent_secondary_contact=parent_secondary_contact,
                    parent_email=parent_email,
                    file=file_name
                )
                db.add(bursary_class)
                db.flush()  # Flush to get the ID without committing

                # Create participant info records
                if participant_info:
                    for participant in participant_info:
                        bursary_details = BursaryClassFormDetails(
                            bursary_class_id=bursary_class.id,
                            participant_id=participant.get('participant_id'),
                            course_id=participant.get('course_id'),
                            age=participant.get('age'),
                            programme_applying_for=participant.get('programme_applying_for')
                        )
                        db.add(bursary_details)

                db.commit()
                db.refresh(bursary_class)
                return bursary_class

        except Exception as e:
            raise GenericError(status_code=422, exc=f"Could not create bursary class form: {str(e)}")

    def list_all_bursary_class(self):
        """Fetch all bursary class forms with participant details"""
        try:
            with get_db() as db:
                records = db.query(BursaryClassForm).options(
                    joinedload(BursaryClassForm.participant_details)
                ).filter(
                    BursaryClassForm.deleted_at.is_(None)
                ).all()

                result = []
                for record in records:
                    form_data = BursaryClassFormResponseSchema.model_validate(record).model_dump()
                    result.append(form_data)

                return result

        except Exception as e:
            raise GenericError(status_code=500, exc=f"Error fetching bursary class forms: {str(e)}")

    def fetch_bursary_clas_details(self, bursary_class_id: int):
        """Fetch details of a specific bursary class form"""
        try:
            with get_db() as db:
                record = db.query(BursaryClassForm).options(
                    joinedload(BursaryClassForm.participant_details)
                ).filter(
                    and_(
                        BursaryClassForm.id == bursary_class_id,
                        BursaryClassForm.deleted_at.is_(None)
                    )
                ).first()

                if not record:
                    raise GenericError(status_code=404, exc="Bursary class form not found")

                return BursaryClassFormResponseSchema.model_validate(record).model_dump()

        except GenericError:
            raise
        except Exception as e:
            raise GenericError(status_code=500, exc=f"Error fetching bursary class details: {str(e)}")

    async def update_bursary_class(
        self,
        bursary_class_id: int,
        parent_id: int,
        parent_primary_contact: str,
        parent_secondary_contact: Optional[str] = None,
        parent_email: Optional[str] = None,
        file=None
    ):
        """Update bursary class form"""
        try:
            file_name = await self.upload_file(file) if file else None

            with get_db() as db:
                bursary_class = db.query(BursaryClassForm).filter(
                    and_(
                        BursaryClassForm.id == bursary_class_id,
                        BursaryClassForm.deleted_at.is_(None)
                    )
                ).first()

                if not bursary_class:
                    raise GenericError(status_code=404, exc="Bursary class form not found")

                # Update fields
                bursary_class.parent_id = parent_id
                bursary_class.parent_primary_contact = parent_primary_contact
                bursary_class.parent_secondary_contact = parent_secondary_contact
                bursary_class.parent_email = parent_email

                if file_name:
                    bursary_class.file = file_name

                db.commit()
                db.refresh(bursary_class)

                return bursary_class

        except GenericError:
            raise
        except Exception as e:
            raise GenericError(status_code=422, exc=f"Could not update bursary class form: {str(e)}")

    def delete_bursary_class(self, bursary_class_id: int):
        """Soft delete bursary class form"""
        try:
            with get_db() as db:
                bursary_class = db.query(BursaryClassForm).filter(
                    and_(
                        BursaryClassForm.id == bursary_class_id,
                        BursaryClassForm.deleted_at.is_(None)
                    )
                ).first()

                if not bursary_class:
                    raise GenericError(status_code=404, exc="Bursary class form not found")

                bursary_class.deleted_at = datetime.now(timezone.utc)
                db.commit()

                return {"message": "Bursary class form deleted successfully"}

        except GenericError:
            raise
        except Exception as e:
            raise GenericError(status_code=422, exc=f"Could not delete bursary class form: {str(e)}")
