from __future__ import annotations

from pathlib import Path
from typing import Any, Dict, Optional

from .models.gemini import Gemini
from ADFmentor.utils.processor import analyze_adf
from ADFmentor.utils.checker import get_file_by_type, is_adf_project
from .utils.path_handler import prepare_answer_path
from .utils.question_parser import parse_lesson_questions


class ADFMentor:
    def __init__(self, api_key: str, model_name: str = "gemini-2.0-flash-exp", model: Optional[Gemini] = None):
        if model is None:
            model = Gemini(api_key=api_key, model_name=model_name)
        self.model = model

    def _evaluate_pipeline_from_path(self, working_path: str, question: Optional[str], prompt: str) -> Optional[
        Dict[str, Any]]:
        if question is None:
            return None

        path = Path(working_path)

        if path.is_file() and path.suffix.lower() == ".json":
            adf_path = path
        elif path.is_dir():
            if is_adf_project(str(path)):
                adf_path = path
            else:
                json_file = get_file_by_type(working_path, ".json")
                if not json_file:
                    return {
                        "score": 0,
                        "feedback": (
                            "Unable to evaluate submission.\n\n"
                            "The assignment includes ADF pipeline questions, but no ADF project files (JSON) were found. "
                            "Please ensure your submission includes all required components and resubmit."
                        ),
                    }
                # Use the whole directory so analyze_adf can rglob all .json files
                adf_path = path
        else:
            return {
                "score": 0,
                "feedback": (
                    "Unable to evaluate submission.\n\n"
                    "The assignment includes ADF pipeline questions, but no ADF project files were found. "
                    "Please ensure your submission includes all required components and resubmit."
                ),
            }

        return self.model.evaluate(
            question=question,
            answer=analyze_adf(str(adf_path)),
            prompt=prompt,
        )

    def _evaluate_write_from_path(self, working_path: str, question: Optional[str], prompt: str) -> Optional[
        Dict[str, Any]]:
        if question is None:
            return None

        path = Path(working_path)

        if path.is_file() and path.suffix.lower() == ".txt":
            txt_path = path
        else:
            txt_file = get_file_by_type(working_path, ".txt")
            if not txt_file:
                return {
                    "score": 0,
                    "feedback": (
                        "Unable to evaluate submission.\n\n"
                        "The assignment includes written type questions, but no written type response (TXT file) was found. "
                        "Please ensure your submission includes all required components and resubmit."
                    ),
                }
            txt_path = path / txt_file

        text_answer = txt_path.read_text(encoding="utf-8")

        return self.model.evaluate(
            question=question,
            answer=text_answer,
            prompt=prompt,
        )

    def evaluate_all(self, answer_path: str, questions: str, prompts: Dict[str, str]) -> Dict[str, Any]:
        working_path = prepare_answer_path(answer_path)

        questions = parse_lesson_questions(questions)

        results = {
            "pipeline": self._evaluate_pipeline_from_path(working_path, questions.get("pipeline"), prompts.get("pipeline")),
            "text": self._evaluate_write_from_path(working_path, questions.get("text"), prompts.get("text")),
        }

        scores = []
        feedback_parts = []

        for key, value in results.items():
            if value is not None:
                scores.append(value['score'])
                feedback_parts.append(
                    f"{'=' * 70}\n"
                    f"{key.upper()} EVALUATION\n"
                    f"{'=' * 70}\n"
                    f"Score: {value['score']}/100\n\n"
                    f"{value['feedback']}\n"
                )

        avg_score = sum(scores) / len(scores) if scores else 0

        summary = {
            'score': round(avg_score, 2),
            'feedback': '\n'.join(feedback_parts) if feedback_parts else "No evaluations completed."
        }

        return summary