import logging
import os
from typing import List, Dict, Optional
from fastapi import HTTPException
import sys
import json
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from core import StudentNationality, Models
from services.pgvector_service import PGVectorService
from services.openai_service import OpenAIService
from services.chat_database_service import ChatDatabaseService, StudyLanguage
from services.pedagogy_service import PedagogyService
from services.connection_pool import ConnectionPool
from services.agent_helpers.query_handlers import QueryHandler
from services.agent_helpers.context_generator import ContextGenerator
from services.agent_helpers.response_generator import ResponseGenerator
from services.agent_helpers.tashkeel_agent import TashkeelAgent
from services.agent_helpers.tashkeel_fixer import apply_fixes, custom_fixes
from services.tts.tts_manager import get_tts_service

logger = logging.getLogger(__name__)

class AgentService:
    """Main service class for handling AI agent conversations with modular architecture"""

    def __init__(self, use_pgvector: bool = True, pool_handler: Optional[ConnectionPool] = None):
        # Initialize core services
        self.openai_service = OpenAIService()
        if not self.openai_service.is_available():
            logger.warning("Warning: OPENAI_API_KEY not found. Agent service will be disabled.")
        
        self.tts_service = get_tts_service(self.openai_service)
        if not self.tts_service.is_available():
            logger.warning("Warning: No TTS service is available.")

        # Database setup
        self.pool_handler = pool_handler
        if self.pool_handler is None:
            self.pool_handler = ConnectionPool(
                minconn=1,
                maxconn=20,
                dbname=os.getenv("DB_NAME"),
                user=os.getenv("DB_USER"),
                password=os.getenv("DB_PASSWORD"),
                host=os.getenv("DB_HOST"),
                port=os.getenv("DB_PORT")
            )
        
        self.db_service = ChatDatabaseService(self.pool_handler)
        
        # PGVector setup
        self.use_pgvector = use_pgvector
        if self.use_pgvector:
            self.pgvector = PGVectorService(self.pool_handler)
            self.pgvector.setup_curriculum_table()
        else:
            self.pgvector = None

        self.pedagogy_service = PedagogyService()
        
        # Initialize modular components
        self.query_handler = QueryHandler(self.openai_service, self.pgvector, self.db_service)
        self.context_generator = ContextGenerator(self.openai_service, self.pgvector)
        self.response_generator = ResponseGenerator(
            self.openai_service, self.db_service, self.pedagogy_service,
            self.query_handler, self.context_generator
        )

        self.tashkeel_agent = TashkeelAgent(self.openai_service)


    def is_available(self) -> bool:
        return self.openai_service.is_available()



    def generate_response(self, user_message: str, student_id: str, subject: str = "Science", 
                         model: str = Models.chat, temperature: float = 0.3, top_k: int = 3) -> str:
        """Main response generation method"""
        response = self.response_generator.generate_response(
            user_message, student_id, subject, model, temperature, top_k
        )
        response = apply_fixes(response, custom_fixes)
        #response = self.tashkeel_agent.apply_tashkeel(response)
        print(f"response: {response}")
        return response


    def close(self):
        """Close database connection pools"""
        if self.pool_handler:
            try:
                self.pool_handler.close_all()
            except Exception as e:
                logger.error(f"Error closing connection pools: {e}")


    def generate_and_store_mcqs(
        self, grade: int, subject: str, unit: str, concept: str, is_arabic: bool, num_questions: int = 5
    ) -> List[Dict]:
        """
        Generates NEW, UNIQUE MCQs for a topic by first retrieving existing ones
        and instructing the AI to avoid generating duplicates.
        """
        if not self.pgvector:
            raise HTTPException(status_code=503, detail="Vector service is not available for context retrieval.")

        # === STEP 1: RETRIEVE EXISTING QUESTIONS ===
        logger.info(f"Checking for existing questions for: {grade}/{subject}/{unit}/{concept}")
        existing_questions = self.pgvector.get_mcqs(
            grade, subject, unit, concept, is_arabic, limit=None # Fetch ALL existing questions
        )
        
        existing_questions_text = "No existing questions found."
        if existing_questions:
            # Format the existing questions into a simple list for the prompt
            q_list = [f"- {q['question_text']}" for q in existing_questions]
            existing_questions_text = "\n".join(q_list)
            logger.info(f"Found {len(existing_questions)} existing questions. Will instruct AI to generate different ones.")

        # === STEP 2: RETRIEVE CURRICULUM CONTEXT ===
        search_query = f"summary of {concept} in {unit}"
        query_embedding = self.openai_service.generate_embedding(search_query)
        
        context_chunks = self.pgvector.search_filtered_nearest(
            query_embedding, grade, subject, is_arabic, limit=10 
        )
        
        if not context_chunks:
            raise HTTPException(status_code=404, detail="No curriculum context found for this topic in the specified language.")
            
        full_context = "\n---\n".join([chunk['chunk_text'] for chunk in context_chunks])
        

        # === STEP 3: CREATE THE ADVANCED, AWARE PROMPT ===
        if is_arabic:
            prompt = f"""
            أنت خبير في تطوير المناهج ومهمتك إنشاء أسئلة اختيار من متعدد جديدة ومختلفة.
            
            هذه هي الأسئلة الموجودة حاليًا في قاعدة البيانات حول المفهوم "{concept}":
            --- الأسئلة الحالية ---
            {existing_questions_text}
            --- نهاية الأسئلة الحالية ---

            اعتمادًا فقط على السياق التالي من المنهج:
            --- السياق ---
            {full_context}
            --- نهاية السياق ---
            
            يرجى توليد {num_questions} من أسئلة الاختيار من متعدد **الجديدة والمختلفة تمامًا** عن الأسئلة الموجودة أعلاه.
            يجب أن تكون كل الأسئلة قابلة للإجابة مباشرة من السياق المقدم.
            
            يجب أن يكون ردك مصفوفة JSON صحيحة. كل كائن يجب أن يحتوي على المفاتيح التالية:
            - "question_text": نص السؤال.
            - "correct_answer": الإجابة الصحيحة.
            - "wrong_answer_1": إجابة خاطئة.
            - "wrong_answer_2": إجابة خاطئة.
            - "wrong_answer_3": إجابة خاطئة.
            
            لا تكتب أي نص أو شرح خارج مصفوفة الـ JSON.
            """
        else:
            prompt = f"""
            You are an expert curriculum developer tasked with creating new and unique multiple-choice questions.

            Here are the questions that ALREADY EXIST in the database for the concept "{concept}":
            --- EXISTING QUESTIONS ---
            {existing_questions_text}
            --- END EXISTING QUESTIONS ---

            Based ONLY on the following context from the curriculum:
            --- CONTEXT ---
            {full_context}
            --- END CONTEXT ---
            
            Please generate {num_questions} NEW and COMPLETELY DIFFERENT multiple-choice questions from the list of existing ones above.
            Each question must be answerable directly from the provided context. The questions and all answers MUST be in English.
            
            Your response MUST be a valid JSON array of objects with these keys:
            - "question_text"
            - "correct_answer"
            - "wrong_answer_1"
            - "wrong_answer_2"
            - "wrong_answer_3"
            
            Do not include any text outside of the JSON array.
            """

        # === STEP 4 & 5: CALL LLM, PARSE, and STORE (No changes here) ===
        try:
            # ... (The entire try/except block for calling the LLM remains exactly the same)
            response = self.openai_service.client.chat.completions.create(
                model=Models.chat,
                messages=[{"role": "user", "content": prompt}],
                temperature=0.5, # Slightly higher temp for more creativity
                response_format={"type": "json_object"}
            )
            response_content = response.choices[0].message.content
            json_response = json.loads(response_content)
            
            generated_questions = []
            for key, value in json_response.items():
                if isinstance(value, list):
                    generated_questions = value
                    break
            
            if not generated_questions:
                 raise ValueError("LLM did not return a list of questions in the JSON response.")

        except (json.JSONDecodeError, ValueError, KeyError) as e:
            logger.error(f"Failed to parse MCQ response from LLM: {e}\nRaw Response: {response_content}")
            raise HTTPException(status_code=500, detail="Failed to generate or parse MCQs from AI.")

        mcqs_to_store = []
        for q in generated_questions:
            mcqs_to_store.append({
                "grade": grade, "is_arabic": is_arabic, "subject": subject,
                "unit": unit, "concept": concept, "question_text": q["question_text"],
                "correct_answer": q["correct_answer"], "wrong_answer_1": q["wrong_answer_1"],
                "wrong_answer_2": q["wrong_answer_2"], "wrong_answer_3": q["wrong_answer_3"],
            })
        
        self.pgvector.insert_mcqs(mcqs_to_store)
        
        return mcqs_to_store