"""Course-plan assignments: link a generated plan to a class or students.

Two flavours of assignment:

* ``mode='batch'``  — all current and future students of an ``op.batch``
  see the plan in their student dashboard.
* ``mode='students'`` — only the chosen ``res.users`` (linked through
  the standard ``op.student`` portal user) see it.

The assignment is the visibility unit; it does NOT mutate
enrollment, grades, or schedules. Teachers can attach a due date and a
short message that appears on the student card.
"""

import logging

from odoo import api, fields, models

_logger = logging.getLogger(__name__)


ASSIGNMENT_MODE_SELECTION = [
    ('batch', 'Class / Batch'),
    ('students', 'Specific students'),
    ('entities', 'Entities'),
]

ASSIGNMENT_STATE_SELECTION = [
    ('active', 'Active'),
    ('archived', 'Archived'),
]


class CoursePlanAssignment(models.Model):
    _name = 'encoach.course.plan.assignment'
    _description = 'Course Plan Assignment'
    _order = 'create_date desc, id desc'

    plan_id = fields.Many2one(
        'encoach.course.plan', required=True, ondelete='cascade', index=True,
    )
    mode = fields.Selection(ASSIGNMENT_MODE_SELECTION, required=True, default='batch')

    batch_id = fields.Many2one(
        'op.batch', ondelete='set null', string='Class / batch',
    )
    student_user_ids = fields.Many2many(
        'res.users', 'course_plan_assignment_student_rel',
        'assignment_id', 'user_id', string='Specific students',
    )
    entity_ids = fields.Many2many(
        'encoach.entity', 'course_plan_assignment_entity_rel',
        'assignment_id', 'entity_id', string='Entities',
    )

    assigned_by_id = fields.Many2one(
        'res.users', default=lambda self: self.env.user, string='Assigned by',
    )
    due_date = fields.Date()
    message = fields.Text(help='Optional note shown to the student.')
    state = fields.Selection(ASSIGNMENT_STATE_SELECTION, default='active')

    student_count = fields.Integer(compute='_compute_student_count', store=False)

    @api.depends('mode', 'batch_id', 'student_user_ids', 'entity_ids')
    def _compute_student_count(self):
        Enroll = self.env['op.student.course'].sudo()
        Batch = self.env['op.batch'].sudo()
        for rec in self:
            if rec.mode == 'students':
                rec.student_count = len(rec.student_user_ids)
                continue
            if rec.mode == 'entities':
                user_ids = set()
                for entity in rec.entity_ids:
                    for user in entity.user_ids:
                        if user and user.id:
                            user_ids.add(user.id)
                rec.student_count = len(user_ids)
                continue
            if not rec.batch_id:
                rec.student_count = 0
                continue
            try:
                course_id = Batch.browse(rec.batch_id.id).course_id.id
                if course_id:
                    rec.student_count = Enroll.search_count([
                        ('course_id', '=', course_id),
                        ('batch_id', '=', rec.batch_id.id),
                    ])
                else:
                    rec.student_count = 0
            except Exception:
                rec.student_count = 0

    def expand_user_ids(self):
        """Return the ``res.users`` ids that should see this plan."""
        self.ensure_one()
        if self.mode == 'students':
            return self.student_user_ids.ids
        if self.mode == 'entities':
            user_ids = []
            for entity in self.entity_ids:
                for user in entity.user_ids:
                    if user and user.id:
                        user_ids.append(user.id)
            return list(set(user_ids))
        if self.mode == 'batch' and self.batch_id:
            try:
                Enroll = self.env['op.student.course'].sudo()
                course_id = self.batch_id.course_id.id
                rows = Enroll.search([
                    ('course_id', '=', course_id),
                    ('batch_id', '=', self.batch_id.id),
                ])
                user_ids = []
                for row in rows:
                    student = getattr(row, 'student_id', None)
                    if not student:
                        continue
                    user = getattr(student, 'user_id', None)
                    if user and user.id:
                        user_ids.append(user.id)
                return list(set(user_ids))
            except Exception:
                _logger.exception('expand_user_ids failed for assignment %s', self.id)
                return []
        return []

    def to_api_dict(self):
        self.ensure_one()
        return {
            'id': self.id,
            'plan_id': self.plan_id.id,
            'plan_name': self.plan_id.name or '',
            'mode': self.mode or 'batch',
            'batch_id': self.batch_id.id if self.batch_id else None,
            'batch_name': self.batch_id.name if self.batch_id else '',
            'student_user_ids': self.student_user_ids.ids,
            'student_user_names': [u.name for u in self.student_user_ids],
            'entity_ids': self.entity_ids.ids,
            'entity_names': [e.name for e in self.entity_ids],
            'student_count': self.student_count or 0,
            'assigned_by_id': self.assigned_by_id.id if self.assigned_by_id else None,
            'assigned_by_name': self.assigned_by_id.name if self.assigned_by_id else '',
            'due_date': self.due_date.isoformat() if self.due_date else None,
            'message': self.message or '',
            'state': self.state or 'active',
            'created_at': self.create_date.isoformat() if self.create_date else None,
        }
