from fastapi import HTTPException
import os
from ..utils.hashing import HashGenerator
from user_journey_service.crew import UserJourney 
from user_journey_service.processors.duration_estimator import MicrolearningDurationEstimator
from user_journey_service.processors.user_journey_synthesizer import Synthesizer
from user_journey_service.processors.topic_validator import MicrolearningTopicValidator

duration_estimator = MicrolearningDurationEstimator()
synthesizer = Synthesizer()
topic_validator = MicrolearningTopicValidator()
import re
from user_journey_service.services.defaults_service import DefaultEstimator

class MicrolearningService:
    def __init__(self,input_data):
        self.crew_instance = UserJourney()
        self.input_data = input_data
        self.input_hash = HashGenerator.generate_input_hash(input_data)
        self.research_file = f"research/{self.input_hash}.md"
        self.output_file = f"output/{self.input_hash}.md"
        self.output_file_1 = f"output1/{self.input_hash}.md"
        self.output_file_2 = f"output2/{self.input_hash}.md"
        self.json_output_path = f'parsed_course_content/{self.input_hash}.json'
        self.defaults_dir = f'defaults/{self.input_hash}.md'
        


    # def run_journey(self):
    #     try:
    #         if self._is_first_iteration():
    #             exists,_ = self._fetch_existing_result(self.output_file)
    #             if exists:
    #                 return {"status": "success", "message": "Fetched existing result."}
    #             else:
    #                 print("Need all the Agents..")
    #                 self._execute_first_iteration()
    #         available_time = self._estimate_duration()
    #         content1,content2 = self._load_content_based_feedback()
    #         self._execute_restructure_crew(available_time,content1,content2)
    #         self._combine_user_journeys()
    #         return {"status": "success", "message": "Crew execution completed."}

    def run_journey(self):
        try:
            if self._is_first_iteration():
                exists,result = self._fetch_existing_result(self.output_file)
                if exists:
                    return {"status": "success", "message": "Fetched existing result.","output":result,"hashid":self.input_hash}
                else:
                    if self._validate_the_topic():
                        print("Need all the Agents..")
                    else:
                        print("Invalid topic...")
                        return {"status": "failed", "message": "Invalid topic."}
                    self._execute_first_iteration()
            available_time = self._estimate_duration()
            content1,content2 = self._load_content_based_feedback()
            self._execute_restructure_crew(available_time,content1,content2)
            # self._combine_user_journeys()     ### commented to remove multiple LLM dependency
            exists,result = self._fetch_existing_result(self.output_file)
            return {"status": "success", "message": "Crew execution completed.","output":result,"hashid":self.input_hash}
            

        except Exception as e:
            raise HTTPException(status_code=500, detail=f"Error running crew: {e}")

    def _validate_the_topic(self):
        validate = topic_validator.validate_topic(self.input_data)
        print(f"The validator output is : {validate}")
        normalized = validate.strip().lower()

        if normalized.startswith("valid topic"):
            print("This is a valid topic.")
            return True
        else:
            print("This is an invalid topic.")
            return False
        
    def parse_questions(self,md_text):
        pattern = r"### Q\d+:\s*\n?(.*?)(?=\n### Q\d+:|\Z)"
        return re.findall(pattern, md_text, re.DOTALL)
    
    def _is_first_iteration(self):
        print(f"Inside feedback test : {self.input_data.feedback}")
        if self.input_data.feedback =="First iteration":
            return True
        return False
    
    def _fetch_existing_result(self,file_path):
        if os.path.exists(file_path):
            with open(file_path, 'r') as file:
                result = file.read()
            # print(f"The output is : {result}")
            return True, result
        return False, ""
    
    def _execute_first_iteration(self):
        exists,_ = self._fetch_existing_result(self.research_file)
        if exists:
            print("researcher already exists..")
        else:
            inputs = self.input_data.dict()
            crew = self.crew_instance.researcher_crew(research_file=self.research_file)
            crew.kickoff(inputs=inputs)
        
    def _estimate_duration(self):
        available_time = duration_estimator.estimate_duration(self.input_data)
        if isinstance(available_time, str):
            available_time = available_time.strip("[]")
        available_time = str(available_time) + " minutes"
        print(f"The available time estimated is : {available_time}")
        return available_time

    def _load_content_based_feedback(self):
        if self._is_first_iteration():
            _,content = self._fetch_existing_result(self.research_file)
            return content,content
        else:
            _,content1 = self._fetch_existing_result(self.output_file_1)
            _,content2 = self._fetch_existing_result(self.output_file_2)
            return content1,content2

    def _execute_restructure_crew(self,available_time,content1,content2):
        default_estimator = DefaultEstimator(self.input_data)
        user_defaults = default_estimator.run()
        print(user_defaults["defaults"])
        inputs = self.input_data.dict()
        inputs["content"] = content1
        inputs["available_time"] = available_time
        inputs.update(user_defaults["defaults"])         
        # inputs["filepath"] = self.defaults_dir
        crew = self.crew_instance.restructure_crew1(output_file_1=self.output_file,available_time=available_time,feedback=self.input_data.feedback)   ## output_file_1=self.output_file_1 to use a single LLM, updated like output_file_1=self.output_file
        crew.kickoff(inputs=inputs)

        ## Below 3 lines are commented to remove multiple LLM dependency
        # inputs["content"] = content2
        # crew = self.crew_instance.restructure_crew2(output_file_2=self.output_file_2, available_time=available_time,feedback=self.input_data.feedback)
        # crew.kickoff(inputs=inputs)

    def _combine_user_journeys(self):
        _,user_journey1 = self._fetch_existing_result(self.output_file_1)
        _,user_journey2 = self._fetch_existing_result(self.output_file_2)
        combined_data = synthesizer.review_and_combine(designation=self.input_data.Job_Title,skills=self.input_data.Skills,experience=self.input_data.Experience,content1=user_journey1,content2=user_journey2)
        os.makedirs(os.path.dirname(self.output_file), exist_ok=True)
        with open(self.output_file, 'w', encoding='utf-8') as out_file:
            out_file.write(combined_data)
        







        
