import logging
from odoo import http
from odoo.http import request
from odoo.addons.encoach_api.controllers.base import (
    jwt_required, _json_response, _error_response, _paginate,
)

_logger = logging.getLogger(__name__)


class StudentProgressController(http.Controller):
    """
    Institutional "Student Progress" view.

    Aggregates per-student totals across the key OpenEduCat operational
    records an admin cares about at a glance:

    - total_attendance      → number of op.attendance.line rows (i.e. sessions
                              attended or at least registered for)
    - total_attendance_present → subset where present=True (best-effort, some
                              OpenEduCat variants store this differently)
    - total_assignment      → number of op.assignment.sub.line rows
    - total_marksheet_line  → number of op.marksheet.line rows
    - total_admissions      → number of op.admission rows (if the student was
                              admitted through the admission workflow)

    The endpoint returns one row per op.student.  Search (?q=) and batch
    (?batch_id=) / course (?course_id=) filters are supported so the page
    stays usable at scale.
    """

    @http.route('/api/student-progress', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_progress(self, **kw):
        try:
            env = request.env
            Student = env['op.student'].sudo() if 'op.student' in env else None
            if Student is None:
                return _json_response({'items': [], 'data': [], 'total': 0, 'page': 1, 'size': 0})

            offset, limit, page = _paginate(kw)
            domain = [('active', '=', True)] if 'active' in Student._fields else []
            q = (kw.get('q') or '').strip()
            if q:
                domain += ['|',
                           ('partner_id.name', 'ilike', q),
                           ('gr_no', 'ilike', q)]
            batch_id = kw.get('batch_id')
            if batch_id:
                try:
                    bid = int(batch_id)
                    if 'course_detail_ids' in Student._fields:
                        domain.append(('course_detail_ids.batch_id', '=', bid))
                except Exception:
                    pass
            course_id = kw.get('course_id')
            if course_id:
                try:
                    cid = int(course_id)
                    if 'course_detail_ids' in Student._fields:
                        domain.append(('course_detail_ids.course_id', '=', cid))
                except Exception:
                    pass

            total = Student.search_count(domain)
            students = Student.search(domain, offset=offset, limit=limit, order='id asc')

            AttLine = env['op.attendance.line'].sudo() if 'op.attendance.line' in env else None
            AsgSub = env['op.assignment.sub.line'].sudo() if 'op.assignment.sub.line' in env else None
            MsLine = env['op.marksheet.line'].sudo() if 'op.marksheet.line' in env else None
            Admission = env['op.admission'].sudo() if 'op.admission' in env else None

            items = []
            for s in students:
                sid = s.id
                partner = s.partner_id if 'partner_id' in s._fields else False
                student_name = partner.name if partner else (s.display_name or '')

                total_attendance = 0
                total_attendance_present = 0
                if AttLine is not None:
                    try:
                        total_attendance = AttLine.search_count([('student_id', '=', sid)])
                        if 'present' in AttLine._fields:
                            total_attendance_present = AttLine.search_count(
                                [('student_id', '=', sid), ('present', '=', True)]
                            )
                        elif 'attendance' in AttLine._fields:
                            total_attendance_present = AttLine.search_count(
                                [('student_id', '=', sid), ('attendance', '=', True)]
                            )
                    except Exception:
                        pass

                total_assignment = 0
                if AsgSub is not None:
                    try:
                        total_assignment = AsgSub.search_count([('student_id', '=', sid)])
                    except Exception:
                        pass

                total_marksheet_line = 0
                avg_marks = None
                if MsLine is not None:
                    try:
                        lines = MsLine.search([('student_id', '=', sid)])
                        total_marksheet_line = len(lines)
                        if lines and 'marks' in MsLine._fields:
                            marks = [float(l.marks or 0) for l in lines]
                            if marks:
                                avg_marks = round(sum(marks) / len(marks), 2)
                    except Exception:
                        pass

                total_admissions = 0
                if Admission is not None:
                    try:
                        total_admissions = Admission.search_count([('student_id', '=', sid)])
                    except Exception:
                        pass

                attendance_rate = None
                if total_attendance:
                    attendance_rate = round(
                        (total_attendance_present / total_attendance) * 100, 1
                    )

                items.append({
                    'id': sid,
                    'student_id': sid,
                    'student_name': student_name,
                    'gr_no': getattr(s, 'gr_no', '') or '',
                    'total_attendance': total_attendance,
                    'total_attendance_present': total_attendance_present,
                    'attendance_rate': attendance_rate,
                    'total_assignment': total_assignment,
                    'total_marksheet_line': total_marksheet_line,
                    'avg_marks': avg_marks,
                    'total_admissions': total_admissions,
                })

            return _json_response({
                'items': items,
                'data': items,
                'total': total,
                'page': page,
                'size': limit,
            })
        except Exception as e:
            _logger.exception('list_progress')
            return _error_response(str(e), 500)

    @http.route('/api/student-progress/<int:sid>', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def get_progress(self, sid, **kw):
        """Detailed per-student breakdown (lines, not just totals)."""
        try:
            env = request.env
            if 'op.student' not in env:
                return _error_response('op.student model not installed', 404)
            student = env['op.student'].sudo().browse(sid)
            if not student.exists():
                return _error_response('Student not found', 404)

            partner = student.partner_id if 'partner_id' in student._fields else False
            out = {
                'id': student.id,
                'student_name': partner.name if partner else (student.display_name or ''),
                'gr_no': getattr(student, 'gr_no', '') or '',
                'attendance': [],
                'assignments': [],
                'marksheets': [],
            }

            if 'op.attendance.line' in env:
                AL = env['op.attendance.line'].sudo()
                lines = AL.search([('student_id', '=', sid)], limit=100, order='id desc')
                for l in lines:
                    present = None
                    if 'present' in AL._fields:
                        present = bool(l.present)
                    elif 'attendance' in AL._fields:
                        present = bool(l.attendance)
                    out['attendance'].append({
                        'id': l.id,
                        'sheet': l.attendance_id.display_name if 'attendance_id' in l._fields and l.attendance_id else '',
                        'present': present,
                    })

            if 'op.assignment.sub.line' in env:
                AS = env['op.assignment.sub.line'].sudo()
                lines = AS.search([('student_id', '=', sid)], limit=100, order='id desc')
                for l in lines:
                    out['assignments'].append({
                        'id': l.id,
                        'assignment': l.assignment_id.display_name if 'assignment_id' in l._fields and l.assignment_id else '',
                        'marks': float(getattr(l, 'marks', 0) or 0),
                        'state': getattr(l, 'state', '') or '',
                    })

            if 'op.marksheet.line' in env:
                ML = env['op.marksheet.line'].sudo()
                lines = ML.search([('student_id', '=', sid)], limit=100, order='id desc')
                for l in lines:
                    out['marksheets'].append({
                        'id': l.id,
                        'marksheet': l.marksheet_reg_id.display_name if 'marksheet_reg_id' in l._fields and l.marksheet_reg_id else '',
                        'marks': float(getattr(l, 'marks', 0) or 0),
                        'grade': getattr(l, 'grade', '') or '',
                    })

            return _json_response(out)
        except Exception as e:
            _logger.exception('get_progress')
            return _error_response(str(e), 500)
