import logging
from odoo import models, fields, api

_logger = logging.getLogger(__name__)


class EncoachCourseChapter(models.Model):
    _name = 'encoach.course.chapter'
    _description = 'Course Chapter'
    _order = 'sequence, id'

    name = fields.Char(required=True)
    course_id = fields.Many2one('op.course', required=True, ondelete='cascade')
    sequence = fields.Integer(default=10)
    description = fields.Text()
    start_date = fields.Date()
    end_date = fields.Date()
    unlock_mode = fields.Selection([
        ('auto_date', 'Automatic by Date'),
        ('manual', 'Manual'),
        ('prerequisite', 'Prerequisite'),
    ], default='manual')
    is_unlocked = fields.Boolean(default=True)
    topic_id = fields.Many2one('encoach.topic', ondelete='set null')
    domain_id = fields.Many2one(
        'encoach.domain', compute='_compute_domain_id', store=True,
        ondelete='set null', string='Domain',
    )
    learning_objective_ids = fields.Many2many(
        'encoach.learning.objective', 'encoach_chapter_obj_rel',
        'chapter_id', 'objective_id', string='Learning Objectives',
    )
    material_ids = fields.One2many('encoach.chapter.material', 'chapter_id')
    material_count = fields.Integer(compute='_compute_material_count', store=True)

    @api.depends('topic_id', 'topic_id.domain_id')
    def _compute_domain_id(self):
        for rec in self:
            rec.domain_id = rec.topic_id.domain_id.id if rec.topic_id and rec.topic_id.domain_id else False

    @api.depends('material_ids')
    def _compute_material_count(self):
        for rec in self:
            rec.material_count = len(rec.material_ids)


class EncoachChapterMaterial(models.Model):
    _name = 'encoach.chapter.material'
    _description = 'Chapter Material'
    _order = 'sequence, id'

    name = fields.Char(required=True)
    chapter_id = fields.Many2one('encoach.course.chapter', required=True, ondelete='cascade')
    type = fields.Selection([
        ('pdf', 'PDF'),
        ('document', 'Document'),
        ('video', 'Video'),
        ('audio', 'Audio'),
        ('image', 'Image'),
        ('link', 'Link'),
        ('article', 'Article'),
    ], default='pdf')
    file_data = fields.Binary(attachment=True)
    file_name = fields.Char()
    url = fields.Char()
    description = fields.Text()
    sequence = fields.Integer(default=10)
    allow_download = fields.Boolean(default=True)
    is_book = fields.Boolean(default=False)
    book_chapters = fields.Text()
    resource_id = fields.Many2one('encoach.resource', ondelete='set null',
                                  help="Auto-created library resource mirror")

    @api.model_create_multi
    def create(self, vals_list):
        records = super().create(vals_list)
        records._vector_index()
        records._sync_library_resource()
        return records

    def write(self, vals):
        res = super().write(vals)
        if self.env.context.get('no_sync'):
            return res
        if any(f in vals for f in ('name', 'description', 'type')):
            self._vector_index()
        sync_fields = ('name', 'type', 'url', 'file_data')
        if any(f in vals for f in sync_fields):
            self._sync_library_resource()
        return res

    def unlink(self):
        self._vector_delete()
        resources = self.mapped('resource_id').filtered('exists')
        res = super().unlink()
        resources.unlink()
        return res

    def _sync_library_resource(self):
        """Create or update a matching encoach.resource for each material, propagating taxonomy."""
        Res = self.env.get('encoach.resource')
        if Res is None:
            return
        Res = self.env['encoach.resource'].sudo()
        type_map = {
            'pdf': 'pdf', 'document': 'document', 'video': 'video',
            'audio': 'pdf', 'image': 'pdf', 'link': 'link', 'article': 'document',
        }
        for rec in self:
            vals = {
                'name': rec.name,
                'type': type_map.get(rec.type, 'document'),
                'url': rec.url or '',
                'review_status': 'approved',
            }
            if rec.file_data:
                vals['file'] = rec.file_data
            chapter = rec.chapter_id
            if chapter:
                if chapter.topic_id:
                    vals['topic_ids'] = [(4, chapter.topic_id.id)]
                if chapter.domain_id:
                    vals['domain_id'] = chapter.domain_id.id
                course = chapter.course_id
                if course and hasattr(course, 'encoach_subject_id') and course.encoach_subject_id:
                    vals['subject_id'] = course.encoach_subject_id.id
                if chapter.learning_objective_ids:
                    vals['learning_objective_ids'] = [(6, 0, chapter.learning_objective_ids.ids)]
            if rec.resource_id and rec.resource_id.exists():
                rec.resource_id.write(vals)
            else:
                new_res = Res.create(vals)
                rec.with_context(no_sync=True).write({'resource_id': new_res.id})

    def _vector_index(self):
        """Index material into the vector store for RAG retrieval with full taxonomy context."""
        try:
            svc_mod = self.env.get('encoach.embedding')
            if svc_mod is None:
                return
            from odoo.addons.encoach_vector.services.embedding_service import EmbeddingService
            svc = EmbeddingService(self.env)
            for rec in self:
                parts = [rec.name or '']
                if rec.description:
                    parts.append(str(rec.description)[:2000])
                chapter = rec.chapter_id
                if chapter:
                    if chapter.course_id:
                        parts.append(f"Course: {chapter.course_id.name}")
                    parts.append(f"Chapter: {chapter.name}")
                    if chapter.topic_id:
                        parts.append(f"Topic: {chapter.topic_id.name}")
                    if chapter.domain_id:
                        parts.append(f"Domain: {chapter.domain_id.name}")
                    course = chapter.course_id
                    if course and hasattr(course, 'encoach_subject_id') and course.encoach_subject_id:
                        parts.append(f"Subject: {course.encoach_subject_id.name}")
                    for obj in chapter.learning_objective_ids:
                        parts.append(f"Objective: {obj.name}")
                text = ' '.join(p for p in parts if p).strip()
                if text:
                    metadata = {'type': rec.type or 'pdf'}
                    if chapter:
                        metadata['chapter_id'] = chapter.id
                        metadata['chapter_name'] = chapter.name or ''
                        if chapter.course_id:
                            metadata['course_id'] = chapter.course_id.id
                            metadata['course_name'] = chapter.course_id.name or ''
                        if chapter.topic_id:
                            metadata['topic_id'] = chapter.topic_id.id
                            metadata['topic_name'] = chapter.topic_id.name or ''
                        if chapter.domain_id:
                            metadata['domain_id'] = chapter.domain_id.id
                            metadata['domain_name'] = chapter.domain_id.name or ''
                        course = chapter.course_id
                        if course and hasattr(course, 'encoach_subject_id') and course.encoach_subject_id:
                            metadata['subject_id'] = course.encoach_subject_id.id
                            metadata['subject_name'] = course.encoach_subject_id.name or ''
                        if chapter.learning_objective_ids:
                            metadata['objective_ids'] = chapter.learning_objective_ids.ids
                            metadata['objective_names'] = chapter.learning_objective_ids.mapped('name')
                    svc.upsert('material', rec.id, text, metadata)
            self.env.cr.commit()
        except Exception:
            _logger.warning("Failed to vector-index material(s)", exc_info=True)

    def _vector_delete(self):
        """Remove material embeddings from the vector store."""
        try:
            svc_mod = self.env.get('encoach.embedding')
            if svc_mod is None:
                return
            from odoo.addons.encoach_vector.services.embedding_service import EmbeddingService
            svc = EmbeddingService(self.env)
            for rec in self:
                svc.delete('material', rec.id)
        except Exception:
            _logger.warning("Failed to delete material vector(s)", exc_info=True)


class EncoachChapterProgress(models.Model):
    _name = 'encoach.chapter.progress'
    _description = 'Chapter Progress'
    _rec_name = 'chapter_id'

    student_id = fields.Many2one('op.student', required=True, ondelete='cascade')
    chapter_id = fields.Many2one('encoach.course.chapter', required=True, ondelete='cascade')
    status = fields.Selection([
        ('not_started', 'Not Started'),
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
    ], default='not_started')
    started_at = fields.Datetime()
    completed_at = fields.Datetime()
    materials_completed = fields.Integer(default=0)
    materials_total = fields.Integer(default=0)


class EncoachCourseCompletion(models.Model):
    _name = 'encoach.course.completion'
    _description = 'Course Completion'
    _rec_name = 'course_id'

    student_id = fields.Many2one('op.student', required=True, ondelete='cascade')
    course_id = fields.Many2one('op.course', required=True, ondelete='cascade')
    status = fields.Selection([
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
    ], default='in_progress')
    chapters_total = fields.Integer(default=0)
    chapters_completed = fields.Integer(default=0)
    progress_percent = fields.Integer(default=0)
    completed_at = fields.Datetime()
    post_test_available = fields.Boolean(default=False)
