from .service import get_service
from googleapiclient.errors import HttpError
from typing import Optional, Literal, List

def create_google_classroom(owner_id: str, classroom_name: str, subject: Optional[str]= None, description: Optional[str]= None, section: Optional[str]= None, room: Optional[str]= None) -> dict:
    """
    Create a new note in Google Keep.

    Args:
        owner_id (str): The owner of the classroom. Works fine when passed "me".
        classroom_name (str): The name of the Classroom.
        subject (str, optional): The subject of the Classroom.
        description (str, optional): The description of the Google Classroom.
        section (str, optional): The section of the Classroom. Defaults to None.
        room (str, optional): The room of the Classroom. Defaults to None.

    Returns:
        dict: Confirmation of note creation and note metadata. The id that is returned in the response is
        important field as all other functions need course_id.
    
    Example:
        ```python
        def test_create_classroom():
            try:
                classroom = create_google_classroom(
                    owner_id= "me",
                    classroom_name= 'Test',
                    subject= 'Test Subject',
                    description= 'This is a test note created for unit testing.',
                    section= 'A',
                    room= '101'
                )
                assert classroom is not None
                return f'Test case passed: {classroom}'
            except Exception as e:
                return f'Error creating classroom: {e}'
        ```
    """
    try:
        service = get_service(service_name= 'classroom')
        course = {
            "owner_id": owner_id,
            "name": classroom_name,
            "section": section,
            "description": description,
            "room": room,
            "subject": subject
        }
        course = service.courses().create(body=course).execute()
        return course
    except HttpError as error:
        return {'Error': error}

def get_classroom_details(course_id: str) -> dict:
    """
    To get the details about the classroom using the course id that was returned when creating the classroom.
    It will give you details like:
        - Name
        - Section
        - Description
        - Enrollment code
        and many other values.
    Args:
        course_id (str): The ID of the Classroom that you received when creating the classroom.
        
    Returns:
        dict: Details of the classroom.
    
    Example:
        ```python
        def test_get_classroom_details():
            try:
                classroom = get_classroom_details(
                    course_id= "818379112875",
                )
                assert classroom is not None
                return f'Test case passed: {classroom}'
            except Exception as e:
                return f'Error creating invite: {e}'
        ```
    """
    try:
        service = get_service(service_name= 'classroom')
        course = service.courses().get(id=course_id).execute()
        return  course
    except HttpError as error:
        return {'Error': error}

def invite_user_to_classroom(course_id: str, user_email: str, role: Literal['admin', 'student', 'teacher'] = 'student') -> dict:
    """
    To add the user to the classroom.
    It will firstly check if that student or teacher is already enrolled if not only then it will send the invite.

    Args:
        course_id (str): The ID of the Classroom that you received when creating the classroom.
        user_email (str): The email address of the user to invite.
        role (str, optional): The role of the user. User can be student, teacher, or admin. Defaults to 'student'.

    Returns:
        dict: Confirmation of user creation and user metadata.
    
    Example:
        ```python
        def test_invite_user_to_classroom():
            try:
                invite = invite_user_to_classroom(
                    course_id= "818379112875",
                    user_email= 'dsaworld33@gmail.com',
                    role= 'teacher',
                )
                assert invite is not None
                return f'Test case passed: {invite}'
            except Exception as e:
                return f'Error creating invite: {e}'
        ```
    """
    try:
        service = get_service(service_name= 'classroom')
        if role== 'student':
            existing_students_data= get_students(course_id= course_id)
            students_emails= []
            for student in existing_students_data:
                students_emails.append(student['profile']['emailAddress'])
            if user_email in students_emails:
                return {'Message': 'This student is already enrolled.'}
        elif role== 'teacher':
            existing_teachers_data= get_teachers(course_id= course_id)
            teachers_emails= []
            for teacher in existing_teachers_data:
                teachers_emails.append(teacher['profile']['emailAddress'])
            if user_email in teachers_emails:
                return {'Message': 'This teacher is already enrolled.'}
        invitation= {
            "user_id": user_email,
            "course_id": course_id,
            "role": role
        }
        response = service.invitations().create(body=invitation).execute()
        return response
    except HttpError as error:
        return {'Error': error}

def create_assignment(course_id: str, title: str, description: str, materials: Optional[List]) -> dict:
    """
    To create a new coursework assignment.

    Args:
        course_id (str): The ID of the course.
        title (str): The title of the coursework.
        description (str): The description of the coursework.
        materials (Optional[List]): The materials of the coursework. It will be a list of nested dictionaries. Like this:
            [
                {"link": {"url": "http://example.com"}},
                {"link": {"url": "http://example.com"}},
            ]
        
    Example:
        ```python
        def test_create_assignment():
            try:
                assignment = create_assignment(
                    course_id= "818379112875",
                    title= 'Test Assignment',
                    description= 'A test assignment created for unit testing.',
                    materials= [
                        {"link": {"url": "https://docs.google.com/document/d/1IVcw5OxVJstVUlCKVy4Ap4TOmsn75gjGejt_9TlkkZ0/edit?usp=drive_link"}}
                    ]
                )
                assert assignment is not None
                return f'Test case passed: {assignment}'
            except Exception as e:
                return f'Error creating assignment: {e}'
        ```
    """
    try:
        service = get_service(service_name= 'classroom')
        coursework = {
            "title": title,
            "description": description,
            "materials": materials,
            "workType": "ASSIGNMENT",
            "state": "PUBLISHED",
        }
        coursework = (
            service.courses()
            .courseWork()
            .create(courseId=course_id, body=coursework)
            .execute()
        )
        print(f"Assignment created with ID {coursework.get('id')}")
        return coursework

    except HttpError as error:
        print(f"An error occurred: {error}")
        return {'Error': error}

def add_teacher(course_id: str, teachers_email: str):
    """
    Function for adding a teacher to a classroom. Only admin role user can add the teacher directly.
    The difference between invite_user_to_classroom is that invite sends an invitation email and the
    role can be selected dynamically. (Means you can send invitation of student, teacher, admin from
    that single function.)
    But in this you can only add teacher, and it will be directly added without any invite.

    One thing to note here is that this function might give error if you are using normal gmail account,
    to add users you should have a domain account.

    Args:
        course_id (str): The ID of the course.
        teachers_email (str): The email of the teacher to add the student to.

    Returns:
        dict: Confirmation of student creation and student metadata.
    
    Example:
        ```python
        def test_add_teacher():
            try:
                teacher= add_teacher(
                    course_id= "818379112875",
                    teachers_email= 'jmm.usmanyaqoob@gmail.com',
                )
                assert teacher is not None
                return f'Test case passed: {teacher}'
            except Exception as e:
                return f'Error adding teacher: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        teacher = {"userId": teachers_email}
        teacher_addition = (
            service.courses()
            .teachers()
            .create(
                courseId= course_id, body= teacher
            )
            .execute()
        )
        return teacher_addition
    except HttpError as error:
        return {'Error': error}

def add_student(course_id: str, student_email: str):
    """
    Function for adding a student to a classroom. Only admin and teacher role user can add the student directly.

    One thing to note here is that this function might give error if you are using normal gmail account,
    to add users you should have a domain account.

    Args:
        course_id (str): The ID of the course.
        student_email (str): The email of the user to add the student to.

    Returns:
        dict: Confirmation of student creation and student metadata.
    
    Example:
        ```python
        def test_add_student():
            try:
                student= add_student(
                    course_id= "818379112875",
                    student_email= 'jmm.usmanyaqoob@gmail.com',
                )
                assert student is not None
                return f'Test case passed: {student}'
            except Exception as e:
                return f'Error adding student: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        student = {"userId": student_email}
        student_addition = (
            service.courses()
            .students()
            .create(
                courseId= course_id, body= student
            )
            .execute()
        )
        return student_addition
    except HttpError as error:
        return {'Error': error}

def join_classroom(course_id: str, student_email: str):
    """
    Function for joining the classroom as student. You can directly join the classroom as student only.

    One thing to note here is that this function might give error if you are using normal gmail account,
    to add users you should have a domain account.

    Args:
        course_id (str): The ID of the course.
        student_email (str): The email of the user to add the student to.

    Returns:
        dict: Confirmation of student joining.
    
    Example:
        ```python
        def test_join_classroom():
            try:
                join= join_classroom(
                    course_id= "818379112875",
                    student_email= 'jmm.usmanyaqoob@gmail.com'
                )
                assert join is not None
                return f'Test case passed: {join}'
            except Exception as e:
                return f'Error joining classroom: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        enrollment_code= get_classroom_details(course_id= course_id)['enrollmentCode']
        student = {"userId": student_email}
        student_join = (
            service.courses()
            .students()
            .create(
                courseId= course_id, enrollmentCode= enrollment_code, body= student
            )
            .execute()
        )
        return student_join
    except HttpError as error:
        return {'Error': error}

def get_students(course_id: str) -> List:
    """
    To get the list of the students that are enrolled in the Google Classroom.
    It will return a list of dictionaries with all details like email, name, id of the students.

    Args:
        course_id (str): The ID of the course.

    Returns:
        list: List of the students that are enrolled in the Google Classroom.
    
    Example:
        ```python
        def test_get_students():
            try:
                students= get_students(
                    course_id= "818379112875"
                )
                assert students is not None
                return f'Test case passed: {students}'
            except Exception as e:
                return f'Error getting students list: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        response = service.courses().students().list(courseId= course_id).execute()
        return response['students']
    except HttpError as error:
        raise ValueError(f'Error getting student list: {error}')

def get_teachers(course_id: str) -> List:
    """
    To get the list of the teachers that are enrolled in the Google Classroom.
    It will return a list of dictionaries with all details like email, name, id of the teachers.

    Args:
        course_id (str): The ID of the course.

    Returns:
        list: List of the students that are enrolled in the Google Classroom.
    
    Example:
        ```python
        def test_get_teachers():
            try:
                teachers= get_teachers(
                    course_id= "818379112875"
                )
                assert teachers is not None
                return f'Test case passed: {teachers}'
            except Exception as e:
                return f'Error getting teachers list: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        response = service.courses().teachers().list(courseId= course_id).execute()
        return response['teachers']
    except HttpError as error:
        raise ValueError(f'Error getting teachers list: {error}')

def delete_student(course_id: str, student_email: str) -> dict:
    """
    To delete the student in the Google Classroom. This function will firstly check if
    student that is to be deleted is even enrolled in the Google Classroom or not.

    Args:
        course_id (str): The ID of the course.
        student_email (str): The email of the student to delete.

    Returns:
        dict: Confirmation of classroom deletion.
    
    Example:
        ```python
        def test_delete_student():
            try:
                deletion= delete_student(
                    course_id= "818379112875",
                    student_email='dsaworld33@gmail.com'
                )
                assert deletion is not None
                return f'Test case passed: {deletion}'
            except Exception as e:
                return f'Error deletion of student: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        existing_students_data = get_students(course_id=course_id)
        existing_students_emails = []
        for student in existing_students_data:
            existing_students_emails.append(student['profile']['emailAddress'])
        if student_email in existing_students_emails:
            service.courses().students().delete(courseId= course_id,
                                                userId= student_email).execute()
            return {'status': 'success', 'message': 'Student deleted'}
        else:
            return {'status': 'Failed', 'message': 'The mentioned student email is not enrolled in the Classroom.'}
    except HttpError as error:
        return {'Error': error}

def delete_teacher(course_id: str, teacher_email: str) -> dict:
    """
    To delete the teacher in the Google Classroom. This function will firstly check if
    teacher that is to be deleted is even enrolled in the Google Classroom or not.

    Args:
        course_id (str): The ID of the course.
        teacher_email (str): The email of the student to delete.

    Returns:
        dict: Confirmation of classroom deletion.
    
    Example:
        ```python
        def test_delete_teacher():
            try:
                deletion= delete_teacher(
                    course_id= "818379112875",
                    teacher_email='dsaworld33@gmail.com'
                )
                assert deletion is not None
                return f'Test case passed: {deletion}'
            except Exception as e:
                return f'Error deletion of teacher: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        existing_teachers_data = get_teachers(course_id=course_id)
        existing_teachers_emails = []
        for teacher in existing_teachers_data:
            existing_teachers_emails.append(teacher['profile']['emailAddress'])
        if teacher_email in existing_teachers_emails:
            service.courses().teachers().delete(courseId= course_id,
                                                userId= teacher_email).execute()
            return {'status': 'success', 'message': 'Teacher deleted'}
        else:
            return {'status': 'Failed', 'message': 'The mentioned teacher email is not enrolled in the Classroom.'}
    except HttpError as error:
        return {'Error': error}

def list_classrooms():
    """
    This function will list all the classroom you are part of. It will return the list of dictionaries with
    all the details about the classrooms that you are enrolled in.

    Returns:
        List of the classroom you are part of.
    
    Example:
        ```python
        def test_list_classrooms():
            try:
                classrooms= list_classrooms()
                return f'Test case passed: {classrooms}'
            except Exception as e:
                return f'Error getting the classrooms: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        courses = []
        page_token = None
        while True:
            response = (
                service.courses().list(pageToken=page_token, pageSize=100).execute()
            )
            courses.extend(response.get("courses", []))
            page_token = response.get("nextPageToken", None)
            if not page_token:
                break
        if not courses:
            return []
        return courses
    except HttpError as error:
        return error

def delete_classroom(course_id: str) -> dict:
    """
    To delete the Google Classroom using the classroom or course id. This function will firstly check if
    you are even a part of that classroom or not. I think only admin and teacher can delete the classroom (not sure about this).

    One more thing that you cannot delete the course with status as ACTIVE so we will make the status ARCHIVED and then delete it.

    Args:
        course_id (str): The ID of the course.

    Returns:
        dict: Confirmation of classroom deletion.
    
    Example:
        ```python
        def test_delete_classroom():
            try:
                deletion= delete_classroom(
                    course_id= "818379112875")
                assert deletion is not None
                return f'Test case passed: {deletion}'
            except Exception as e:
                return f'Error deletion of classroom: {e}'
        ```
    """
    try:
        service= get_service(service_name= 'classroom')
        existing_classrooms= list_classrooms()
        existing_classrooms_ids = []
        for classroom in existing_classrooms:
            existing_classrooms_ids.append(classroom['id'])
        if course_id in existing_classrooms_ids:
            service.courses().patch(
                id= course_id,
                updateMask= "courseState",
                body= {"courseState": "ARCHIVED"}
            ).execute()
            service.courses().delete(id= course_id).execute()
            return {'status': 'success', 'message': 'classroom deleted'}
        else:
            return {'status': 'Failed', 'message': 'classroom does not exist.'}
    except HttpError as error:
        return {'Error': error}

