import pickle
import logging
import random

logging.basicConfig(level=logging.DEBUG)

def get_recommendations(client_id, user_data):
    try:
        # Load the trained model from a file
        with open(f"trained_models/model_{client_id}.pkl", "rb") as file:
            trained_model = pickle.load(file)

        user_id = list(user_data.keys())[0]
        logging.debug(f"User ID: {user_id}")
        courses_data = trained_model['courses_data']
        competency_data = trained_model['competency_data']
        users_data = trained_model['users_data']
        top_rated_courses = trained_model['top_rated_courses']
        logging.debug(f"Courses Data: {courses_data}")

        recommendations = []

        assigned_courses = set(user_data[user_id]['assignedCourses'])
        completed_courses = set(user_data[user_id]['completedCourses'])
        user_skills = {skill['skill_id']: int(skill['skill_type']) for skill in user_data[user_id]['skills']}
        manager_id = user_data[user_id].get('managerId')
        logging.debug(f"User Skills: {user_skills}, Manager ID: {manager_id}")

        # Check if the user is completely new
        if not assigned_courses and not completed_courses and not user_skills and not manager_id:
            logging.info("User is completely new. Providing top-rated course recommendations.")
            for course in top_rated_courses:
                if course['lms_course_id'] not in assigned_courses and course['lms_course_id'] not in completed_courses:
                    recommendations.append({
                        'courseId': course['lms_course_id'],
                        'score': 1,
                        'reason': 'Top-rated course for new user'
                    })
            return recommendations[:10]

        # User has a manager ID but no other data
        if not assigned_courses and not completed_courses and not user_skills and manager_id:
            logging.info("User has only manager ID. Attempting collaborative filtering recommendations.")
            if manager_id in users_data:
                users_under_manager = [uid for uid, data in users_data.items() if data.get('managerId') == manager_id]
                for uid in users_under_manager:
                    if uid != user_id:
                        user_assigned_courses = users_data[uid]['assignedCourses']
                        for course_id in user_assigned_courses:
                            if course_id not in assigned_courses and course_id not in completed_courses:
                                recommendations.append({
                                    'courseId': course_id,
                                    'score': 0.8,
                                    'reason': f"Recommended based on collaborative filtering with users under the same manager."
                                })
                if recommendations:
                    return recommendations[:10]

            logging.info("Insufficient data for collaborative filtering. Falling back to top-rated courses.")
            for course in top_rated_courses:
                if course['lms_course_id'] not in assigned_courses and course['lms_course_id'] not in completed_courses:
                    recommendations.append({
                        'courseId': course['lms_course_id'],
                        'score': 1,
                        'reason': 'Top-rated course for new user'
                    })
            return recommendations[:10]

        # Recommendations based on upgrading user skills
        if user_skills:
            for skill_id, skill_type in user_skills.items():
                for course in courses_data:
                    if 'skills' in course:
                        for course_skill in course['skills']:
                            if course_skill['skill_id'] == skill_id and int(course_skill['skill_type']) > skill_type:
                                recommendations.append({
                                    'courseId': course['courseId'],
                                    'score': 1,
                                    'reason': f"Recommended for upgrading existing user skills. Skill to improve: {skill_id}"
                                })

        logging.debug(f"Recommendations based on upgrading skills: {recommendations}")

        # Recommendations based on competency data
        for skill_id, skill_type in user_skills.items():
            parent_matched = False
            child_matched = False
            for parent_skill_data in competency_data:
                parent_skill_id = parent_skill_data['parent_skill_id']
                child_skills = parent_skill_data['child_skills']
                if skill_id == parent_skill_id:
                    parent_matched = True
                    for child_skill_id in child_skills:
                        for course in courses_data:
                            if 'skills' in course:
                                for course_skill in course['skills']:
                                    if course_skill['skill_id'] == child_skill_id:
                                        recommendations.append({
                                            'courseId': course['courseId'],
                                            'score': 0.9,
                                            'reason': f"Recommended based on competency data matching with user skills. Matched skill: {child_skill_id}"
                                        })
            if not parent_matched:
                for parent_skill_data in competency_data:
                    child_skills = parent_skill_data['child_skills']
                    if skill_id in child_skills:
                        child_matched = True
                        for course in courses_data:
                            if 'skills' in course:
                                for course_skill in course['skills']:
                                    if course_skill['skill_id'] == skill_id:
                                        recommendations.append({
                                            'courseId': course['courseId'],
                                            'score': 0.9,
                                            'reason': f"Recommended based on competency data matching with user skills. Matched skill: {skill_id}"
                                        })
            if not parent_matched and not child_matched:
                for course in courses_data:
                    if 'skills' in course:
                        for course_skill in course['skills']:
                            if course_skill['skill_id'] == skill_id:
                                recommendations.append({
                                    'courseId': course['courseId'],
                                    'score': 0.85,
                                    'reason': f"Recommended based on individual skill matching. Matched skill: {skill_id}"
                                })

        logging.debug(f"Recommendations based on competency data: {recommendations}")

        # Recommendations based on assigned and completed courses
        similar_courses_based_on_assigned_completed = set()
        for course in courses_data:
            course_id = course['courseId']
            if course_id not in assigned_courses and course_id not in completed_courses:
                similar_courses_based_on_assigned_completed.add(course_id)

        for course_id in similar_courses_based_on_assigned_completed:
            recommendations.append({
                'courseId': course_id,
                'score': 0.5,
                'reason': 'Recommended based on similar courses to assigned and completed courses.'
            })

        logging.debug(f"Recommendations based on assigned and completed courses: {recommendations}")

        # Collaborative filtering based on users under the same manager
        if manager_id and manager_id in users_data:
            users_under_manager = [uid for uid, data in users_data.items() if data.get('managerId') == manager_id]
            for uid in users_under_manager:
                if uid != user_id:
                    user_assigned_courses = users_data[uid]['assignedCourses']
                    for course_id in user_assigned_courses:
                        if course_id not in assigned_courses and course_id not in completed_courses:
                            recommendations.append({
                                'courseId': course_id,
                                'score': 0.8,
                                'reason': f"Recommended based on collaborative filtering with users under the same manager."
                            })

        logging.debug(f"Recommendations based on collaborative filtering: {recommendations}")

        # Course matching logic
        for course in courses_data:
            course_id = course['courseId']
            if course_id not in assigned_courses and course_id not in completed_courses:
                score = 0.5
                reason = ''
                if 'name' in course and 'Laravel' in course['name']:
                    score += 0.1
                    reason += 'name matching'
                if 'short_description' in course and 'Laravel' in course['short_description']:
                    score += 0.1
                    reason = 'short description matching' if not reason else reason + ', short description matching'
                if 'description' in course and 'Laravel' in course['description']:
                    score += 0.1
                    reason = 'description matching' if not reason else reason + ', description matching'
                if reason:
                    recommendations.append({'courseId': course_id, 'score': score, 'reason': f"Recommended based on {reason}"})

        logging.debug(f"Final Recommendations: {recommendations}")

        # Filter out duplicate recommendations
        unique_recommendations = []
        seen_course_ids = set()
        for recommendation in recommendations:
            if recommendation['courseId'] not in seen_course_ids:
                unique_recommendations.append(recommendation)
                seen_course_ids.add(recommendation['courseId'])

        # Fill the remaining slots with additional recommendations
        while len(unique_recommendations) < 10:
            additional_course = select_additional_course(courses_data, assigned_courses, completed_courses)
            if additional_course:
                unique_recommendations.append({'courseId': additional_course, 'score': 0, 'reason': 'Additional recommendation'})

        # Sort recommendations by score and normalize scores
        unique_recommendations.sort(key=lambda x: x['score'], reverse=True)
        if unique_recommendations:
            max_score = max(unique_recommendations, key=lambda x: x['score'])['score']
            for recommendation in unique_recommendations:
                recommendation['score'] /= max_score

        return unique_recommendations[:10]

    except Exception as e:
        logging.error(f"Error: {e}")
        return []

def select_additional_course(courses_data, assigned_courses, completed_courses):
    available_courses = [course['courseId'] for course in courses_data
                         if course['courseId'] not in assigned_courses and course['courseId'] not in completed_courses]

    if available_courses:
        additional_course = random.choice(available_courses)
        return additional_course
    else:
        return None
