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, _get_json_body, _paginate,
)

_logger = logging.getLogger(__name__)


def _ser_board(b):
    return {
        'id': b.id,
        'name': b.name or '',
        'course_id': b.course_id.id if b.course_id else 0,
        'course_name': b.course_id.name if b.course_id else '',
        'batch_id': b.batch_id.id if b.batch_id else None,
        'batch_name': b.batch_id.name if b.batch_id else None,
        'chapter_id': b.chapter_id.id if b.chapter_id else None,
        'chapter_name': b.chapter_id.name if b.chapter_id else None,
        'is_enabled': b.is_enabled,
        'allow_student_posts': b.allow_student_posts,
        'post_count': b.post_count or 0,
        'assignment_id': None,
    }


def _ser_post(p):
    return {
        'id': p.id,
        'board_id': p.board_id.id,
        'parent_id': p.parent_id.id if p.parent_id else None,
        'author_id': p.author_id.id,
        'author_name': p.author_id.name or '',
        'author_role': '',
        'title': p.title or '',
        'content': p.content or '',
        'attachment_ids': [],
        'attachment_names': [],
        'is_pinned': p.is_pinned,
        'is_resolved': p.is_resolved,
        'reply_count': len(p.child_ids),
        'created_at': str(p.create_date) if p.create_date else '',
    }


def _ser_announcement(a):
    return {
        'id': a.id,
        'title': a.title or '',
        'content': a.content or '',
        'author_id': a.author_id.id,
        'author_name': a.author_id.name or '',
        'course_id': a.course_id.id if a.course_id else None,
        'course_name': a.course_id.name if a.course_id else None,
        'batch_id': a.batch_id.id if a.batch_id else None,
        'batch_name': a.batch_id.name if a.batch_id else None,
        'priority': a.priority or 'normal',
        'is_published': a.is_published,
        'published_at': str(a.published_at) if a.published_at else None,
        'expires_at': str(a.expires_at) if a.expires_at else None,
        'send_email': a.send_email,
        'attachment_ids': [],
        'attachment_names': [],
    }


def _ser_message(m):
    return {
        'id': m.id,
        'sender_id': m.sender_id.id,
        'sender_name': m.sender_id.name or '',
        'recipient_id': m.recipient_id.id,
        'recipient_name': m.recipient_id.name or '',
        'subject': m.subject or '',
        'content': m.content or '',
        'is_read': m.is_read,
        'read_at': str(m.read_at) if m.read_at else None,
        'attachment_ids': [],
        'attachment_names': [],
        'send_email_copy': m.send_email_copy,
        'created_at': str(m.create_date) if m.create_date else '',
    }


class CommunicationController(http.Controller):

    # ── Discussion Boards ────────────────────────────────────────────

    @http.route('/api/discussion-boards', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_boards(self, **kw):
        try:
            M = request.env['encoach.discussion.board'].sudo()
            domain = []
            if kw.get('course_id'):
                domain.append(('course_id', '=', int(kw['course_id'])))
            if kw.get('batch_id'):
                domain.append(('batch_id', '=', int(kw['batch_id'])))
            recs = M.search(domain, limit=200, order='id desc')
            return _json_response([_ser_board(r) for r in recs])
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/discussion-boards', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_board(self, **kw):
        try:
            body = _get_json_body()
            vals = {'name': body.get('name', '')}
            if body.get('course_id'):
                vals['course_id'] = int(body['course_id'])
            if body.get('batch_id'):
                vals['batch_id'] = int(body['batch_id'])
            rec = request.env['encoach.discussion.board'].sudo().create(vals)
            return _json_response(_ser_board(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/discussion-boards/<int:bid>', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False)
    @jwt_required
    def update_board(self, bid, **kw):
        try:
            rec = request.env['encoach.discussion.board'].sudo().browse(bid)
            if not rec.exists():
                return _error_response('Not found', 404)
            body = _get_json_body()
            vals = {}
            if 'name' in body:
                vals['name'] = body['name']
            if 'is_enabled' in body:
                vals['is_enabled'] = bool(body['is_enabled'])
            if 'allow_student_posts' in body:
                vals['allow_student_posts'] = bool(body['allow_student_posts'])
            if vals:
                rec.write(vals)
            return _json_response(_ser_board(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    # ── Posts ────────────────────────────────────────────────────────

    @http.route('/api/discussion-boards/<int:bid>/posts', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_posts(self, bid, **kw):
        try:
            M = request.env['encoach.discussion.post'].sudo()
            domain = [('board_id', '=', bid), ('parent_id', '=', False)]
            offset, limit, page = _paginate(kw)
            total = M.search_count(domain)
            recs = M.search(domain, offset=offset, limit=limit, order='is_pinned desc, create_date desc')
            items = [_ser_post(r) for r in recs]
            return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/discussion-boards/<int:bid>/posts', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_post(self, bid, **kw):
        try:
            body = _get_json_body()
            vals = {
                'board_id': bid,
                'author_id': request.env.uid,
                'content': body.get('content', ''),
            }
            if body.get('title'):
                vals['title'] = body['title']
            if body.get('parent_id'):
                vals['parent_id'] = int(body['parent_id'])
            rec = request.env['encoach.discussion.post'].sudo().create(vals)
            return _json_response(_ser_post(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/posts/<int:pid>', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False)
    @jwt_required
    def update_post(self, pid, **kw):
        try:
            rec = request.env['encoach.discussion.post'].sudo().browse(pid)
            if not rec.exists():
                return _error_response('Not found', 404)
            body = _get_json_body()
            vals = {}
            if 'content' in body:
                vals['content'] = body['content']
            if 'title' in body:
                vals['title'] = body['title']
            if vals:
                rec.write(vals)
            return _json_response(_ser_post(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/posts/<int:pid>', type='http', auth='public', methods=['DELETE'], csrf=False)
    @jwt_required
    def delete_post(self, pid, **kw):
        try:
            rec = request.env['encoach.discussion.post'].sudo().browse(pid)
            if rec.exists():
                rec.unlink()
            return _json_response({'success': True})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/posts/<int:pid>/pin', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def pin_post(self, pid, **kw):
        try:
            rec = request.env['encoach.discussion.post'].sudo().browse(pid)
            if not rec.exists():
                return _error_response('Not found', 404)
            body = _get_json_body()
            pinned = body.get('pinned', not rec.is_pinned)
            rec.write({'is_pinned': pinned})
            return _json_response(_ser_post(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/posts/<int:pid>/resolve', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def resolve_post(self, pid, **kw):
        try:
            rec = request.env['encoach.discussion.post'].sudo().browse(pid)
            if not rec.exists():
                return _error_response('Not found', 404)
            rec.write({'is_resolved': True})
            return _json_response(_ser_post(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    # ── Announcements ────────────────────────────────────────────────

    @http.route('/api/announcements', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_announcements(self, **kw):
        try:
            M = request.env['encoach.announcement'].sudo()
            domain = []
            if kw.get('course_id'):
                domain.append(('course_id', '=', int(kw['course_id'])))
            if kw.get('priority'):
                domain.append(('priority', '=', kw['priority']))
            recs = M.search(domain, limit=200, order='create_date desc')
            return _json_response([_ser_announcement(r) for r in recs])
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/announcements', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_announcement(self, **kw):
        try:
            body = _get_json_body()
            vals = {
                'title': body.get('title', ''),
                'content': body.get('content', ''),
                'author_id': request.env.uid,
                'priority': body.get('priority', 'normal'),
                'send_email': body.get('send_email', False),
            }
            if body.get('course_id'):
                vals['course_id'] = int(body['course_id'])
            if body.get('batch_id'):
                vals['batch_id'] = int(body['batch_id'])
            if body.get('expires_at'):
                vals['expires_at'] = body['expires_at']
            rec = request.env['encoach.announcement'].sudo().create(vals)
            return _json_response(_ser_announcement(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/announcements/<int:aid>', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False)
    @jwt_required
    def update_announcement(self, aid, **kw):
        try:
            rec = request.env['encoach.announcement'].sudo().browse(aid)
            if not rec.exists():
                return _error_response('Not found', 404)
            body = _get_json_body()
            vals = {}
            for k in ('title', 'content', 'priority', 'expires_at'):
                if k in body:
                    vals[k] = body[k]
            if 'send_email' in body:
                vals['send_email'] = bool(body['send_email'])
            if vals:
                rec.write(vals)
            return _json_response(_ser_announcement(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/announcements/<int:aid>', type='http', auth='public', methods=['DELETE'], csrf=False)
    @jwt_required
    def delete_announcement(self, aid, **kw):
        try:
            rec = request.env['encoach.announcement'].sudo().browse(aid)
            if rec.exists():
                rec.unlink()
            return _json_response({'success': True})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/announcements/<int:aid>/publish', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def publish_announcement(self, aid, **kw):
        try:
            rec = request.env['encoach.announcement'].sudo().browse(aid)
            if not rec.exists():
                return _error_response('Not found', 404)
            from datetime import datetime
            rec.write({'is_published': True, 'published_at': str(datetime.now())})
            return _json_response(_ser_announcement(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    # ── Messages ─────────────────────────────────────────────────────

    @http.route('/api/messages', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_messages(self, **kw):
        try:
            M = request.env['encoach.message'].sudo()
            uid = request.env.uid
            domain = [('recipient_id', '=', uid)]
            if kw.get('is_read') == 'false':
                domain.append(('is_read', '=', False))
            offset, limit, page = _paginate(kw)
            total = M.search_count(domain)
            recs = M.search(domain, offset=offset, limit=limit, order='create_date desc')
            items = [_ser_message(r) for r in recs]
            return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/messages/sent', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_sent_messages(self, **kw):
        try:
            M = request.env['encoach.message'].sudo()
            uid = request.env.uid
            offset, limit, page = _paginate(kw)
            domain = [('sender_id', '=', uid)]
            total = M.search_count(domain)
            recs = M.search(domain, offset=offset, limit=limit, order='create_date desc')
            items = [_ser_message(r) for r in recs]
            return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/messages', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def send_message(self, **kw):
        try:
            body = _get_json_body()
            vals = {
                'sender_id': request.env.uid,
                'recipient_id': int(body.get('recipient_id', 0)),
                'subject': body.get('subject', ''),
                'content': body.get('content', ''),
                'send_email_copy': body.get('send_email_copy', False),
            }
            rec = request.env['encoach.message'].sudo().create(vals)
            return _json_response(_ser_message(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/messages/<int:mid>', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def get_message(self, mid, **kw):
        try:
            rec = request.env['encoach.message'].sudo().browse(mid)
            if not rec.exists():
                return _error_response('Not found', 404)
            if not rec.is_read and rec.recipient_id.id == request.env.uid:
                from datetime import datetime
                rec.write({'is_read': True, 'read_at': str(datetime.now())})
            return _json_response(_ser_message(rec))
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/messages/<int:mid>', type='http', auth='public', methods=['DELETE'], csrf=False)
    @jwt_required
    def delete_message(self, mid, **kw):
        try:
            rec = request.env['encoach.message'].sudo().browse(mid)
            if rec.exists():
                rec.unlink()
            return _json_response({'success': True})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/messages/unread-count', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def unread_count(self, **kw):
        try:
            count = request.env['encoach.message'].sudo().search_count([
                ('recipient_id', '=', request.env.uid),
                ('is_read', '=', False),
            ])
            return _json_response({'count': count})
        except Exception as e:
            return _error_response(str(e), 500)
