import json
import re
from langchain_groq import ChatGroq
from langchain_core.prompts import PromptTemplate
from langchain.chains import LLMChain

def TNA(groq_api_key, goals, problems):
    """
    Analyzes multiple business goals and problems using an LLM to extract required skills with reasoning.

    Args:
        groq_api_key (str): The API key for the Groq service.
        goals (list): A list of business goals (strings).
        problems (list): A list of business problems (strings).

    Returns:
        dict: A dictionary where keys are "Goal: [goal]" or "Problem: [problem]",
              and values are lists of dictionaries containing "Skill" and "Reason".
    """
    llm = ChatGroq(
        model="llama-3.1-8b-instant",
        temperature=0,
        max_tokens=None,
        timeout=None,
        max_retries=2,
        groq_api_key=groq_api_key,
    )

    skill_extraction_prompt = PromptTemplate(
        input_variables=["goals_str", "problems_str"],
        template = """
            You are an expert business consultant with extensive experience in identifying the necessary skills for achieving business goals and solving business problems.

            Given the following business goals:
            {goals_str}

            And the following business problems:
            {problems_str}

            Identify the most critical skills required for each goal and problem, along with a brief reason explaining why each skill is necessary.

            **Output Format Example:**
            Goal: Increase customer retention
            - Skill: Customer Service - Reason: Directly addresses customer interactions and satisfaction.
            - Skill: Communication - Reason: Essential for understanding customer needs and conveying solutions.
            - Skill: Problem-Solving - Reason: Necessary to address customer issues and prevent churn.

            Problem: High employee turnover
            - Skill: Employee Engagement - Reason: Helps keep employees motivated and committed to the company.
            - Skill: Leadership - Reason: Strong leadership fosters a positive work culture.
            - Skill: Compensation Strategy - Reason: Competitive salaries and benefits reduce turnover.

            Ensure the output is structured exactly as shown, without additional text.
        """
    )

    goals_str = "\n".join([f"- {g}" for g in goals])
    problems_str = "\n".join([f"- {p}" for p in problems])

    skill_extraction_chain = LLMChain(llm=llm, prompt=skill_extraction_prompt)
    response = skill_extraction_chain.run(goals_str=goals_str, problems_str=problems_str)

    extracted_skills = {}
    current_item = None

    for line in response.strip().split("\n"):
        line = line.strip()
        if line.startswith("Goal:") or line.startswith("Problem:"):
            current_item = line
            extracted_skills[current_item] = []
        elif line.startswith("- Skill:") and current_item:
            try:
                skill, reason = line.split(" - Reason: ")
                skill_name = skill.replace("- Skill: ", "").strip()
                reason_text = reason.strip()
                extracted_skills[current_item].append({"Skill": skill_name, "Reason": reason_text})
            except ValueError:
                continue  # Skip lines that don't match the expected format

    return extracted_skills


def find_skill_gaps(required_skills_dict, organization_skills):
    """
    Analyzes skill gaps for multiple goals/problems.

    Args:
        required_skills_dict (dict): A dictionary where keys are goals/problems
                                     and values are dictionaries containing "skills" (list) and "reasoning" (str).
        organization_skills (set): A set of the organization's existing skills.

    Returns:
        dict: A dictionary containing skill gap analysis for each goal/problem,
              including existing and missing skills.
    """
    analysis_results = {}
    for item, data in required_skills_dict.items():
        required_skills_set = set(data["skills"])
        missing_skills = required_skills_set - organization_skills
        existing_skills = required_skills_set & organization_skills
        analysis_results[item] = {
            "existing_skills": list(existing_skills),
            "missing_skills": list(missing_skills),
            "skills_reasoning": data["reasoning"]
        }
    return analysis_results

def recommend_courses_llm(groq_api_key, missing_skills_analysis, courses_data):
    """
    Recommends courses for identified missing skills using an LLM, with reasoning.

    Args:
        groq_api_key (str): The API key for the Groq service.
        missing_skills_analysis (dict): A dictionary where keys are goals/problems
                                         and values are dictionaries containing 'missing_skills' and 'skills_reasoning'.
        courses_data (list): A list of dictionaries, where each dictionary represents a course
                             and has 'name' and 'description' keys.

    Returns:
        dict: A dictionary where keys are goals/problems and values are dictionaries
              containing 'missing_skills' and 'suggested_courses' (with reasoning).
    """
    llm = ChatGroq(
        model="llama-3.1-8b-instant",
        temperature=0.3,  # Increased temperature for more varied suggestions
        max_tokens=1000,
        timeout=None,
        max_retries=2,
        groq_api_key=groq_api_key,
        # other params...
    )

    course_recommendation_prompt = PromptTemplate(
        input_variables=["missing_skills_str", "courses_str", "goal_or_problem", "skills_reasoning_str"],
        template="""
            You are an expert learning and development specialist.

            For the following business {goal_or_problem}, the identified missing skills are:
            {missing_skills_str}

            The reasoning behind needing these skills is:
            {skills_reasoning_str}

            Here is a list of available courses with their descriptions:
            {courses_str}

            Based on these missing skills and the reasons why they are needed, recommend the most relevant courses from the list and briefly explain why each recommended course is suitable for addressing the skill gap.

            **Output Format:**
            Recommended Courses:
            - [Course Name 1]: [Brief reason for relevance]
            - [Course Name 2]: [Brief reason for relevance]
            If no relevant courses are found, state "No relevant courses found."
            """
    )

    course_recommendations = {}
    for item, analysis in missing_skills_analysis.items():
        missing_skills = analysis["missing_skills"]
        skills_reasoning_str = analysis["skills_reasoning"]
        if not missing_skills:
            course_recommendations[item] = {"missing_skills": [], "suggested_courses": {}}
            continue

        courses_list_str = "\n".join([f"- {course['name']}: {course['description']}" for course in courses_data])
        missing_skills_str = ", ".join(missing_skills)
        goal_or_problem_type = "goal" if item.startswith("Goal:") else "problem"

        recommendation_chain = LLMChain(llm=llm, prompt=course_recommendation_prompt)
        response = recommendation_chain.run(
            missing_skills_str=missing_skills_str,
            courses_str=courses_list_str,
            goal_or_problem=goal_or_problem_type,
            skills_reasoning_str=skills_reasoning_str
        )

        recommended_courses_block = response.split("Recommended Courses:")[-1].strip()
        suggested_courses_with_reasoning = {}
        for line in recommended_courses_block.split('\n'):
            line = line.strip()
            if line.startswith("-"):
                match = re.match(r"- (.*?): (.*)", line)
                if match:
                    course_name = match.group(1).strip()
                    reason = match.group(2).strip()
                    suggested_courses_with_reasoning[course_name] = reason
                elif "No relevant courses found" in line:
                    suggested_courses_with_reasoning = {}
                    break

        course_recommendations[item] = {
            "missing_skills": missing_skills,
            "suggested_courses": suggested_courses_with_reasoning
        }

    return course_recommendations

# Example Usage
if __name__ == "__main__":
    groq_api_key = "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"  # Replace with your actual Groq API key
    business_goals = [
        "Increase sales in the new Southeast Asia market by 20% in the next fiscal year.",
        "Improve the efficiency of our marketing campaigns.",
    ]
    business_problems = [
        "High customer churn rate.",
        "Lack of effective internal communication.",
    ]

    # Load your data
    try:
        with open("data.json", "r") as f:
            data = json.load(f)
            organization_skills = set(data["organization_skills"])
            courses_data = data["courses"]
    except FileNotFoundError:
        print("Error: 'data.json' not found. Please create this file with organization skills and courses data.")
        exit()
    except json.JSONDecodeError:
        print("Error: Could not decode 'data.json'. Please ensure it is valid JSON.")
        exit()

    # 1. Extract Required Skills with Reasoning using LLM
    required_skills_for_all = TNA(groq_api_key, business_goals, business_problems)
    print("Required Skills for Goals and Problems (with Reasoning):")
    print(required_skills_for_all)
#     for item, data in required_skills_for_all.items():
#         print(f"\n--- {item} ---")
#         print("Skills:", data["skills"])
#         print("Reasoning:\n", data["reasoning"])

    # 2. Identify Skill Gaps
    skill_gap_analysis = find_skill_gaps(required_skills_for_all, organization_skills)
    print("\nSkill Gap Analysis:")
    for item, analysis in skill_gap_analysis.items():
        print(f"\n--- {item} ---")
        print("Existing Skills:", analysis["existing_skills"])
        print("Missing Skills:", analysis["missing_skills"])
        print("Reasoning for Required Skills:\n", analysis["skills_reasoning"])

    # 3. Recommend Courses for Missing Skills with Reasoning using LLM
    course_recommendations = recommend_courses_llm(groq_api_key, skill_gap_analysis, courses_data)
    print("\nCourse Recommendations using LLM (with Reasoning):")
    for item, recommendations in course_recommendations.items():
        print(f"\n--- {item} ---")
        print("Missing Skills:", recommendations["missing_skills"])
        print("Suggested Courses:")
        if recommendations["suggested_courses"]:
            for course, reason in recommendations["suggested_courses"].items():
                print(f"- {course}: {reason}")
        else:
            print("No relevant courses found.")