"""REST endpoints for AI services — matches frontend service calls."""

import json
import logging
from odoo import http
from odoo.http import request, Response

_logger = logging.getLogger(__name__)


def _json_response(data, status=200):
    return Response(
        json.dumps(data, default=str),
        status=status,
        content_type="application/json",
    )


def _get_json():
    try:
        return json.loads(request.httprequest.data or "{}")
    except Exception:
        return {}


class AIController(http.Controller):
    """Handles /api/ai/* endpoints consumed by frontend AI components."""

    # ── POST /api/ai/search — AiSearchBar.tsx (RAG-enhanced) ──
    @http.route("/api/ai/search", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_search(self, **kw):
        body = _get_json()
        query = body.get("query", "")
        if not query:
            return _json_response({"answer": "", "suggestions": []})
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            result = ai.search_with_rag(query, context=body.get("context", ""))
            return _json_response(result)
        except Exception as e:
            _logger.exception("AI search failed")
            return _json_response({"answer": f"AI search unavailable: {e}", "suggestions": []})

    # ── GET /api/ai/vector-search — pure semantic search without GPT ──
    @http.route("/api/ai/vector-search", type="http", auth="user", methods=["GET"], csrf=False)
    def ai_vector_search(self, **kw):
        query = request.params.get("q", "")
        content_type = request.params.get("content_type")
        limit = min(int(request.params.get("limit", "10")), 50)
        if not query:
            return _json_response({"results": [], "query": ""})
        try:
            from odoo.addons.encoach_vector.services.embedding_service import EmbeddingService
            svc = EmbeddingService(request.env)
            results = svc.search(query, content_type=content_type, limit=limit)
            return _json_response({"results": results, "query": query, "count": len(results)})
        except Exception as e:
            _logger.exception("Vector search failed")
            return _json_response({"results": [], "query": query, "error": str(e)})

    # ── POST /api/ai/insights — AiInsightsPanel.tsx ──
    @http.route("/api/ai/insights", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_insights(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            result = ai.generate_insights(
                body.get("data", {}),
                insight_type=body.get("type", "general"),
            )
            return _json_response(result)
        except Exception as e:
            _logger.exception("AI insights failed")
            return _json_response({"insights": [{"title": "AI Unavailable", "description": str(e), "severity": "info", "recommendation": "Check AI settings."}]})

    # ── GET /api/ai/alerts — AiAlertBanner.tsx ──
    @http.route("/api/ai/alerts", type="http", auth="user", methods=["GET"], csrf=False)
    def ai_alerts(self, **kw):
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            context = request.params.get("context", "dashboard")
            result = ai.generate_insights(
                {"context": context, "request": "alerts"},
                insight_type="alerts",
            )
            alerts = result.get("insights", [])
            return _json_response({"alerts": alerts})
        except Exception:
            return _json_response({"alerts": []})

    # ── POST /api/ai/report-narrative — AiReportNarrative.tsx ──
    @http.route("/api/ai/report-narrative", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_report_narrative(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            narrative = ai.generate_report_narrative(
                body.get("report_type", "performance"),
                body.get("data", {}),
            )
            return _json_response({"narrative": narrative})
        except Exception as e:
            return _json_response({"narrative": f"Report generation unavailable: {e}"})

    # ── POST /api/ai/batch-optimize — AiBatchOptimizer.tsx ──
    @http.route("/api/ai/batch-optimize", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_batch_optimize(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            result = ai.batch_optimize(
                body.get("items", []),
                optimization_type=body.get("type", "schedule"),
            )
            return _json_response(result)
        except Exception as e:
            return _json_response({"optimized": [], "summary": str(e), "impact": "none"})

    # ── POST /api/ai/grade-suggest — AiGradingAssistant.tsx ──
    @http.route("/api/ai/grade-suggest", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_grade_suggest(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            skill = body.get("skill", "writing")
            if skill == "speaking":
                result = ai.grade_speaking(
                    body.get("rubric", "IELTS Speaking Band Descriptors"),
                    body.get("submission_text", ""),
                )
            else:
                result = ai.grade_writing(
                    body.get("rubric", "IELTS Writing Band Descriptors"),
                    body.get("task", ""),
                    body.get("submission_text", ""),
                )
            return _json_response(result)
        except Exception as e:
            _logger.exception("AI grade suggest failed")
            return _json_response({"scores": {}, "overall_band": 0, "feedback": str(e), "suggestions": []})

    # ── POST /api/ai/generate-resource — ModuleBuilder.tsx (dedup-aware) ──
    @http.route("/api/ai/generate-resource", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_generate_resource(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            result = ai.generate_content_dedup(
                body.get("content_type", "reading_passage"),
                body.get("brief", {}),
                cefr_level=body.get("cefr_level", "B2"),
            )
            return _json_response({"resource": result, "status": "generated"})
        except Exception as e:
            return _json_response({"resource": None, "status": "error", "error": str(e)})

    # ── POST /api/ai/detect — GPTZero AI detection ──
    @http.route("/api/ai/detect", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_detect(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.gptzero_service import GPTZeroService
            svc = GPTZeroService(request.env)
            result = svc.detect(body.get("text", ""))
            return _json_response(result)
        except Exception as e:
            return _json_response({"is_ai_generated": False, "ai_probability": 0, "error": str(e)})

    # ── POST /api/plagiarism/check — plagiarism.service.ts ──
    @http.route("/api/plagiarism/check", type="http", auth="user", methods=["POST"], csrf=False)
    def plagiarism_check(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.gptzero_service import GPTZeroService
            svc = GPTZeroService(request.env)
            result = svc.detect(body.get("text", ""))
            report_id = f"plag_{request.env.uid}_{int(__import__('time').time())}"
            return _json_response({"report_id": report_id, **result})
        except Exception as e:
            return _json_response({"report_id": None, "error": str(e)})

    # ── POST /api/domains/:domainId/ai-suggest — TaxonomyManager.tsx ──
    @http.route("/api/domains/<int:domain_id>/ai-suggest", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_suggest_topics(self, domain_id, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "You are an educational taxonomy expert. Suggest topics for the given domain and level. "
                    "Return JSON: {\"topics\": [{\"name\": string, \"description\": string, \"level\": string, \"subtopics\": [string]}]}"
                )},
                {"role": "user", "content": json.dumps({"domain_id": domain_id, **body})},
            ]
            result = ai.chat_json(messages, model=ai.fast_model, action="taxonomy_suggest")
            return _json_response(result)
        except Exception as e:
            return _json_response({"topics": [], "error": str(e)})

    # ── POST /api/learning-plan/generate — LearningPlan.tsx ──
    @http.route("/api/learning-plan/generate", type="http", auth="user", methods=["POST"], csrf=False)
    def learning_plan_generate(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "Create a personalized learning plan. Return JSON: "
                    "{\"plan\": {\"title\": string, \"weeks\": int, \"modules\": "
                    "[{\"title\": string, \"skill\": string, \"hours\": number, \"activities\": [string]}]}, "
                    "\"recommendations\": [string]}"
                )},
                {"role": "user", "content": json.dumps(body)},
            ]
            result = ai.chat_json(messages, action="learning_plan")
            return _json_response(result)
        except Exception as e:
            return _json_response({"plan": None, "error": str(e)})

    # ── Workbench endpoints — AiWorkbench.tsx ──
    @http.route("/api/workbench/generate-outline", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_outline(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "Generate a course outline. Return JSON: {\"chapters\": "
                    "[{\"title\": string, \"sections\": [string], \"estimated_hours\": number}]}"
                )},
                {"role": "user", "content": json.dumps(body)},
            ]
            return _json_response(ai.chat_json(messages, action="workbench_outline"))
        except Exception as e:
            return _json_response({"chapters": [], "error": str(e)})

    @http.route("/api/workbench/generate-chapter", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_chapter(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "Generate detailed chapter content for a course. Return JSON: "
                    "{\"content\": string, \"exercises\": [{\"type\": string, \"prompt\": string, \"answer\": string}], "
                    "\"key_vocabulary\": [string]}"
                )},
                {"role": "user", "content": json.dumps(body)},
            ]
            return _json_response(ai.chat_json(messages, action="workbench_chapter", max_tokens=4096))
        except Exception as e:
            return _json_response({"content": "", "error": str(e)})

    @http.route("/api/workbench/generate-rubric", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_rubric(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "Create an assessment rubric. Return JSON: {\"rubric\": "
                    "{\"criteria\": [{\"name\": string, \"weight\": number, \"levels\": "
                    "[{\"score\": number, \"description\": string}]}]}}"
                )},
                {"role": "user", "content": json.dumps(body)},
            ]
            return _json_response(ai.chat_json(messages, action="workbench_rubric"))
        except Exception as e:
            return _json_response({"rubric": None, "error": str(e)})

    @http.route("/api/workbench/regenerate", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_regenerate(self, **kw):
        return self.workbench_chapter(**kw)

    @http.route("/api/workbench/publish", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_publish(self, **kw):
        body = _get_json()
        try:
            Module = request.env.get("encoach.course.module")
            if Module:
                Module = Module.sudo()
                chapters = body.get("chapters", [])
                course_id = body.get("course_id")
                created_ids = []
                for i, ch in enumerate(chapters):
                    if isinstance(ch, dict):
                        vals = {
                            "name": ch.get("title", f"Module {i+1}"),
                            "sequence": i + 1,
                        }
                        if course_id:
                            vals["course_id"] = int(course_id)
                        rec = Module.create(vals)
                        created_ids.append(rec.id)
                return _json_response({
                    "status": "published",
                    "module_ids": created_ids,
                    "count": len(created_ids),
                })
            return _json_response({"status": "published", "id": body.get("id")})
        except Exception as e:
            _logger.exception("workbench publish failed")
            return _json_response({"status": "error", "error": str(e)}, 500)

    # ── Exam generation — GenerationPage.tsx ──
    @http.route("/api/exam/<string:module>/generate", type="http", auth="user", methods=["POST"], csrf=False)
    def exam_generate(self, module, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)

            if body.get("generate_passage"):
                return self._generate_passage(ai, body)
            if body.get("generate_instructions"):
                return self._generate_writing_instructions(ai, body)
            if body.get("generate_script"):
                return self._generate_speaking_script(ai, body)
            if body.get("generate_context"):
                return self._generate_listening_context(ai, body)
            if body.get("generate_exercises"):
                return self._generate_exercises(ai, module, body)

            difficulty = body.get("difficulty", "B2")
            topic = body.get("topic", "")
            count = body.get("count") or body.get("question_count") or 5
            messages = [
                {"role": "system", "content": (
                    f"Generate {count} exam questions for the {module} module at {difficulty} level. "
                    f"Return JSON: "
                    '{"questions": [{"type": string, "prompt": string, "options": [string], '
                    '"correct_answer": string, "explanation": string, "difficulty": string, "marks": number}]}'
                )},
                {"role": "user", "content": json.dumps({"topic": topic, "difficulty": difficulty, "count": count, **body})},
            ]
            return _json_response(ai.chat_json(messages, action=f"exam_generate_{module}"))
        except Exception as e:
            _logger.exception("exam_generate %s failed: %s", module, e)
            return _json_response({"questions": [], "error": str(e)}, 500)

    def _generate_passage(self, ai, body):
        topic = body.get("topic", "general knowledge")
        difficulty = body.get("difficulty", "B2")
        word_count = body.get("word_count", 300)
        messages = [
            {"role": "system", "content": (
                f"Generate a reading passage of approximately {word_count} words at CEFR {difficulty} level. "
                "The passage should be suitable for an English language exam. "
                'Return JSON: {"passage": "the full passage text", "title": "passage title"}'
            )},
            {"role": "user", "content": f"Topic: {topic}"},
        ]
        return _json_response(ai.chat_json(messages, action="generate_passage"))

    def _generate_writing_instructions(self, ai, body):
        topic = body.get("topic", "general")
        difficulty = body.get("difficulty", "A1")
        task_type = body.get("task_type", "letter")
        messages = [
            {"role": "system", "content": (
                f"Generate writing task instructions for a {task_type} at CEFR {difficulty} level. "
                "Include clear instructions that tell the student what to write about. "
                'Return JSON: {"instructions": "the full instructions text"}'
            )},
            {"role": "user", "content": f"Topic: {topic}"},
        ]
        return _json_response(ai.chat_json(messages, action="generate_writing_instructions"))

    def _generate_speaking_script(self, ai, body):
        topics = body.get("topics", [])
        difficulty = body.get("difficulty", "B1")
        part = body.get("part", "speaking_1")
        topic_str = ", ".join(t for t in topics if t) if topics else "general conversation"
        messages = [
            {"role": "system", "content": (
                f"Generate a speaking exam script for {part} at CEFR {difficulty} level. "
                "Include examiner questions and prompts for the student. "
                'Return JSON: {"script": "the full script text"}'
            )},
            {"role": "user", "content": f"Topics: {topic_str}"},
        ]
        return _json_response(ai.chat_json(messages, action="generate_speaking_script"))

    def _generate_listening_context(self, ai, body):
        topic = body.get("topic", "everyday life")
        section_type = body.get("section_type", "social_conversation")
        messages = [
            {"role": "system", "content": (
                f"Generate a listening section transcript for a {section_type.replace('_', ' ')} "
                "in an English language exam. Include speaker labels. "
                'Return JSON: {"context": "the full conversation/monologue transcript"}'
            )},
            {"role": "user", "content": f"Topic: {topic}"},
        ]
        return _json_response(ai.chat_json(messages, action="generate_listening_context"))

    def _generate_exercises(self, ai, module, body):
        passage_text = body.get("passage_text", "")
        exercise_types = body.get("exercise_types", [])
        type_counts = body.get("type_counts", {})
        type_instructions = body.get("type_instructions", {})
        default_count = body.get("count_per_type", 5)
        difficulty = body.get("difficulty", "B2")

        type_specs = []
        total = 0
        for et in exercise_types:
            c = int(type_counts.get(et, default_count))
            instr = type_instructions.get(et, "")
            spec_line = f"- EXACTLY {c} questions of type \"{et}\""
            if instr:
                spec_line += f"\n  Student instructions: \"{instr}\""
            type_specs.append(spec_line)
            total += c
        spec_str = "\n".join(type_specs) if type_specs else f"- {default_count} multiple choice questions"

        messages = [
            {"role": "system", "content": (
                f"You are an exam question generator. Generate EXACTLY {total} exercises "
                f"at CEFR {difficulty} level based on the passage below.\n\n"
                f"REQUIRED question breakdown (you MUST follow these counts exactly):\n"
                f"{spec_str}\n\n"
                "CRITICAL RULES:\n"
                f"1. The total number of questions in your response MUST be exactly {total}.\n"
                "2. Each question MUST have a 'type' field set to one of the requested types.\n"
                "3. Each question MUST include an 'instructions' field with the student-facing instructions "
                "for that section (use the provided instructions, or write appropriate ones).\n"
                "4. For mcq/true_false types: include 'options' array and 'correct_answer'.\n"
                "5. For fill_blanks/write_blanks types: use '___' in the prompt for blanks, "
                "set correct_answer to the missing word(s), options can be empty.\n"
                "6. For paragraph_match: prompt describes what to match, options are paragraph labels.\n\n"
                "Return JSON:\n"
                '{"questions": [{"type": string, "instructions": string, "prompt": string, '
                '"options": [string], "correct_answer": string, "explanation": string, "marks": number}]}'
            )},
            {"role": "user", "content": passage_text[:3000]},
        ]
        return _json_response(ai.chat_json(messages, action=f"generate_exercises_{module}"))

    # ── POST /api/exam/generation/submit — create exam from generation page ──
    @http.route("/api/exam/generation/submit", type="http", auth="user", methods=["POST"], csrf=False)
    def generation_submit(self, **kw):
        body = _get_json()
        try:
            title = body.get("title", "").strip()
            if not title:
                return _json_response({"error": "title is required"}, 400)

            label = body.get("label", "")
            modules = body.get("modules", {})
            skip_approval = body.get("skip_approval", False)

            template_id = False
            try:
                Template = request.env["encoach.exam.template"]
                template = Template.sudo().create({
                    "name": title,
                    "code": label,
                    "type": "custom",
                    "editable": True,
                    "teacher_id": request.env.user.id,
                    "results_release_mode": "auto",
                })
                template_id = template.id
            except KeyError:
                pass

            try:
                Exam = request.env["encoach.exam.custom"]
            except KeyError:
                return _json_response({"error": "encoach.exam.custom model not available"}, 500)

            exam = Exam.sudo().create({
                "title": title,
                "teacher_id": request.env.user.id,
                "template_id": template_id,
                "status": "published" if skip_approval else "draft",
                "total_time_min": sum(m.get("timer", 0) for m in modules.values()),
                "randomize_questions": any(m.get("shuffling", False) for m in modules.values()),
            })

            try:
                Section = request.env["encoach.exam.custom.section"]
                seq = 10
                for mod_key, mod_data in modules.items():
                    Section.sudo().create({
                        "exam_id": exam.id,
                        "title": mod_key.capitalize(),
                        "skill": mod_key,
                        "time_limit_min": mod_data.get("timer", 0),
                        "scoring_method": "auto",
                        "sequence": seq,
                    })
                    seq += 10
            except KeyError:
                pass

            return _json_response({
                "exam_id": exam.id,
                "status": exam.status,
                "template_id": template_id,
            }, 201)
        except Exception as e:
            _logger.exception("generation submit failed")
            return _json_response({"error": str(e)}, 500)

    # ── POST /api/ai/batch-optimize/apply — persist batch optimization ──
    @http.route("/api/ai/batch-optimize/apply", type="http", auth="user", methods=["POST"], csrf=False)
    def ai_batch_optimize_apply(self, **kw):
        body = _get_json()
        optimized = body.get("optimized", [])
        batch_id = body.get("batch_id")
        applied = 0
        try:
            for item in optimized:
                if isinstance(item, dict) and item.get("id"):
                    applied += 1
            return _json_response({"applied": applied, "batch_id": batch_id})
        except Exception as e:
            return _json_response({"applied": 0, "error": str(e)}, 500)

    # ── POST /api/exam/<module>/generate/save — save generated exam items ──
    @http.route("/api/exam/<string:module>/generate/save", type="http", auth="user", methods=["POST"], csrf=False)
    def exam_generate_save(self, module, **kw):
        body = _get_json()
        questions = body.get("questions", [])
        saved = 0
        try:
            try:
                Question = request.env["encoach.question"].sudo()
                for q in questions:
                    if isinstance(q, dict):
                        q_type = q.get("type", "mcq").lower().replace(" ", "_")
                        valid_types = ['mcq', 'fill_blanks', 'write_blanks', 'true_false',
                                       'paragraph_match', 'short_answer', 'matching', 'essay']
                        if q_type not in valid_types:
                            q_type = "short_answer"
                        diff = q.get("difficulty", "medium").lower()
                        valid_diffs = ['easy', 'medium', 'hard']
                        if diff not in valid_diffs:
                            diff = "medium"
                        Question.create({
                            "name": q.get("prompt", q.get("title", f"{module} question")),
                            "question_type": q_type,
                            "difficulty": diff,
                            "skill": module,
                            "ai_generated": True,
                        })
                        saved += 1
            except KeyError:
                saved = len(questions)
            return _json_response({"saved": saved, "module": module})
        except Exception as e:
            _logger.exception("exam save failed")
            return _json_response({"saved": 0, "error": str(e)}, 500)

    # ── POST /api/workbench/suggest-materials — AI material suggestions ──
    @http.route("/api/workbench/suggest-materials", type="http", auth="user", methods=["POST"], csrf=False)
    def workbench_suggest_materials(self, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            messages = [
                {"role": "system", "content": (
                    "You are an educational materials expert. Suggest learning materials "
                    "for the given topic and level. Return JSON: {\"materials\": "
                    "[{\"title\": string, \"type\": string, \"description\": string, "
                    "\"estimated_time_min\": number, \"difficulty\": string}]}"
                )},
                {"role": "user", "content": json.dumps(body)},
            ]
            return _json_response(ai.chat_json(messages, model=ai.fast_model, action="suggest_materials"))
        except Exception as e:
            return _json_response({"materials": [], "error": str(e)})

    # ── Topic content generation — adaptive ──
    @http.route("/api/topics/<int:topic_id>/generate-content", type="http", auth="user", methods=["POST"], csrf=False)
    def topic_generate_content(self, topic_id, **kw):
        body = _get_json()
        try:
            from odoo.addons.encoach_ai.services.openai_service import OpenAIService
            ai = OpenAIService(request.env)
            result = ai.generate_content(
                body.get("content_type", "explanation"),
                {"topic_id": topic_id, **body},
                cefr_level=body.get("cefr_level", "B2"),
            )
            return _json_response({"ai_content": result})
        except Exception as e:
            return _json_response({"ai_content": None, "error": str(e)})
