#include <string>
#include <iostream>

using namespace std;

// Forward declarations
class Course;
class Student;
class Instructor;

// Constants for maximum limits
const int MAX_COURSES = 10;
const int MAX_STUDENTS = 30;
const int MAX_INSTRUCTORS = 10;

// 1. Person (Abstract Base Class)
class Person {
protected:
    string name;
    string ID;
    string email;
    string role;  // Role will be either "student", "instructor", or "admin"

public:
    Person(const string& name, const string& ID, const string& email, const string& role) 
        : name(name), ID(ID), email(email), role(role) {}

    virtual void displayInfo() = 0;
    virtual string getRole() { return role; }
    virtual void sendNotification(const string& message) = 0;
};

// 2. Student (Derived from Person)
class Student : public Person {
public:
    string enrolledCourses[MAX_COURSES];  // List of courses student is enrolled in
    int numCourses = 0;  // Counter for enrolled courses

    Student(const string& name, const string& ID, const string& email) 
        : Person(name, ID, email, "student") {}

    void enrollInCourse(const string& course) {
        if (numCourses < MAX_COURSES) {
            enrolledCourses[numCourses++] = course;
            cout << name << " has enrolled in " << course << "." << endl;
        } else {
            cout << "Cannot enroll in more courses." << endl;
        }
    }

    void displayInfo() override {
        cout << "Student ID: " << ID << ", Name: " << name << ", Email: " << email << endl;
        cout << "Enrolled Courses: ";
        for (int i = 0; i < numCourses; i++) {
            cout << enrolledCourses[i] << " ";
        }
        cout << endl;
    }
    
    void sendNotification(const string& message) override {
        cout << "Notification to Student: " << message << endl;
    }
};

// 3. Instructor (Derived from Person)
class Instructor : public Person {
public:
    Instructor(const string& name, const string& ID, const string& email) 
        : Person(name, ID, email, "instructor") {}

    void displayInfo() override {
        cout << "Instructor ID: " << ID << ", Name: " << name << ", Email: " << email << endl;
    }
    
    void sendNotification(const string& message) override {
        cout << "Notification to Instructor: " << message << endl;
    }
};

// 4. Course Class
class Course {
public:
    string courseName;
    string courseDetails;
    Instructor instructor;  // Associated instructor
    Student enrolledStudents[MAX_STUDENTS];  // Students enrolled in the course
    int numStudents = 0;  // Counter for enrolled students

    Course(const string& name, const string& details, const Instructor& instr) 
        : courseName(name), courseDetails(details), instructor(instr) {}

    void displayCourseInfo() {
        cout << "Course Name: " << courseName << ", Instructor: " << instructor.name << endl;
        cout << "Enrolled Students: ";
        for (int i = 0; i < numStudents; i++) {
            cout << enrolledStudents[i].name << " ";
        }
        cout << endl;
    }
};

// 5. Admin (Derived from Person)
class Admin : public Person {
public:
    Admin(const string& name, const string& ID, const string& email) 
        : Person(name, ID, email, "admin") {}

    void displayInfo() override {
        cout << "Admin ID: " << ID << ", Name: " << name << ", Email: " << email << endl;
    }

    void viewCourses(const Course courses[], int courseCount) {
        cout << "Available Courses:" << endl;
        for (int i = 0; i < courseCount; i++) {
            courses[i].displayCourseInfo();
        }
    }

    void addCourse(Course courses[], int& courseCount) {
        if (courseCount >= MAX_COURSES) {
            cout << "Maximum number of courses reached." << endl;
            return;
        }

        string name, details;

        cout << "Enter Course Name: ";
        cin.ignore();
        getline(cin, name);
        cout << "Enter Course Details: ";
        getline(cin, details);
        
        // Create a new instructor for the course
        Instructor newInstructor("Instructor_" + to_string(courseCount), "instructor" + to_string(courseCount), "instructor" + to_string(courseCount) + "@parhopk.com");
        
        // Create the course and add it to the array
        courses[courseCount++] = Course(name, details, newInstructor);
        
        cout << "Course added successfully." << endl;
    }

    void removeCourse(Course courses[], int& courseCount) {
        if (courseCount <= 0) {
            cout << "No courses available to remove." << endl;
            return;
        }

        cout << "Current Courses:" << endl;
        for (int i = 0; i < courseCount; i++) {
            cout << i + 1 << ". " << courses[i].courseName << endl;
        }

        int choice;
        cout << "Select course number to remove: ";
        cin >> choice;

        if (choice > 0 && choice <= courseCount) {
            // Shift courses to remove the selected one
            for (int i = choice - 1; i < courseCount - 1; ++i) {
                courses[i] = courses[i + 1];
            }
            courseCount--;  
            cout << "Course removed successfully." << endl;
        } else {
            cout << "Invalid course number." << endl;
        }
    }
};

// Function prototypes
void displayMenu();
void signUp(Student students[], int& studentCount, Instructor instructors[], int& instructorCount);
void login(const Student students[], int studentCount, const Instructor instructors[], int instructorCount, Admin& admin, Course courses[], int& courseCount);
void adminFunctions(Admin& admin, Student students[], int& studentCount, Instructor instructors[], int& instructorCount, Course courses[], int& courseCount);
void courseManagement(Student& student, Course courses[], int& courseCount);

// Main Function
int main() {
    Student students[MAX_STUDENTS];
    Instructor instructors[MAX_INSTRUCTORS];
    Course courses[MAX_COURSES];  
    int studentCount = 0, instructorCount = 0, courseCount = 0; 

    Admin admin("Admin", "admin01", "admin@parhopk.com");

    int choice;

    // Main menu loop
    while (true) {
        displayMenu();
        cout << "Enter your choice (1-3): ";
        cin >> choice;

        switch (choice) {
            case 1:
                signUp(students, studentCount, instructors, instructorCount);
                break;
            case 2:
                login(students, studentCount, instructors, instructorCount, admin, courses, courseCount);
                break;
            case 3:
                cout << "Exiting the program. Thank you for using ParhoPK!" << endl;
                return 0; // Exit the program
            default:
                cout << "Invalid choice! Please enter a number between 1 and 3." << endl;
        }
    }
    
    return 0;
}

void displayMenu() {
    cout << "===============================" << endl;
    cout << "       Welcome to ParhoPK      " << endl;
    cout << "===============================" << endl;
    cout << "1. Sign Up" << endl;
    cout << "2. Login" << endl;
    cout << "3. Exit" << endl;
}

// Sign-Up Functionality
void signUp(Student students[], int& studentCount, Instructor instructors[], int& instructorCount) {
    int roleChoice;
    cout << "Choose your role: 1. Student 2. Instructor: ";
    cin >> roleChoice;

    string name, ID, email;
    cout << "Enter Name: ";
    cin.ignore();
    getline(cin, name);
    cout << "Enter ID: ";
    cin >> ID;
    cout << "Enter Email: ";
    cin >> email;

    if (roleChoice == 1) {
        if (studentCount < MAX_STUDENTS) {
            students[studentCount++] = Student(name, ID, email);
            cout << "Student signed up successfully!" << endl;
        } else {
            cout << "Maximum number of students reached." << endl;
        }
    } else if (roleChoice == 2) {
        if (instructorCount < MAX_INSTRUCTORS) {
            instructors[instructorCount++] = Instructor(name, ID, email);
            cout << "Instructor signed up successfully!" << endl;
        } else {
            cout << "Maximum number of instructors reached." << endl;
        }
    } else {
        cout << "Invalid role choice." << endl;
    }
}

// Login Functionality
void login(const Student students[], int studentCount, const Instructor instructors[], int instructorCount, Admin& admin, Course courses[], int& courseCount) {
    string ID, email;
    cout << "Enter ID: ";
    cin >> ID;
    cout << "Enter Email: ";
    cin >> email;

    // Check for Admin
    if (admin.ID == ID) {
        string adminEmail;
        cout << "Enter Admin Email: ";
        cin >> adminEmail;
        if (adminEmail == admin.ID) {
            cout << "Admin logged in successfully!" << endl;
            adminFunctions(admin, students, studentCount, instructors, instructorCount, courses, courseCount);
            return;
        }
    }

    // Check for Student
    for (int i = 0; i < studentCount; i++) {
        if (students[i].ID == ID && students[i].email == email) {
            cout << "Student logged in successfully!" << endl;
            courseManagement(const_cast<Student&>(students[i]), courses, courseCount);
            return;
        }
    }

    // Check for Instructor
    for (int i = 0; i < instructorCount; i++) {
        if (instructors[i].ID == ID && instructors[i].email == email) {
            cout << "Instructor logged in successfully!" << endl;
            instructors[i].displayInfo();
            return;
        }
    }
    
    cout << "Invalid ID or Email." << endl;
}

// Admin Functions
void adminFunctions(Admin& admin, Student students[], int& studentCount, Instructor instructors[], int& instructorCount, Course courses[], int& courseCount) {
    int choice;
    while (true) {
        cout << "\nAdmin Menu:" << endl;
        cout << "1. View Courses" << endl;
        cout << "2. Manage Courses" << endl;
        cout << "3. Return to Home Page" << endl;
        cout << "Enter your choice: ";
        cin >> choice;

        switch (choice) {
            case 1:
                admin.viewCourses(courses, courseCount);
                break;
            case 2: {
                int manageChoice;
                while (true) {
                    cout << "\nManage Courses Menu:" << endl;
                    cout << "1. Add Course" << endl;
                    cout << "2. Remove Course" << endl;
                    cout << "3. Return" << endl;
                    cout << "Enter your choice: ";
                    cin >> manageChoice;

                    switch (manageChoice) {
                        case 1:
                            admin.addCourse(courses, courseCount);
                            break;
                        case 2:
                            admin.removeCourse(courses, courseCount);
                            break;
                        case 3:
                            break;
                        default:
                            cout << "Invalid choice! Please enter a number between 1 and 3." << endl;
                    }

                    if (manageChoice == 3) break; // Return to Admin Menu
                }
                break;
            }
            case 3:
                cout << "Returning to Home Page." << endl;
                return; // Exit admin functions
            default:
                cout << "Invalid choice! Please enter a number between 1 and 3." << endl;
        }
    }
}

// Course Management for Students
void courseManagement(Student& student, Course courses[], int& courseCount) {
    int choice;
    while (true) {
        cout << "\nManage Courses:" << endl;
        for (int i = 0; i < courseCount; ++i) {
            cout << i + 1 << ". " << courses[i].courseName << endl;
        }
        cout << "Enter course number to enroll (0 to exit): ";
        cin >> choice;

        if (choice == 0) {
            break;
        } else {
            if (choice > 0 && choice <= courseCount) {
                student.enrollInCourse(courses[choice - 1].courseName);
                courses[choice - 1].enrolledStudents[courses[choice - 1].numStudents++] = student;  // Add student to the course
            } else {
                cout << "Invalid course number." << endl;
            }
        }
    }
}