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__)


class LibraryController(http.Controller):

    # ── Media ────────────────────────────────────────────────────────

    @http.route('/api/library/media', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_media(self, **kw):
        try:
            M = request.env['op.media'].sudo()
            offset, limit, page = _paginate(kw)
            total = M.search_count([])
            recs = M.search([], offset=offset, limit=limit, order='id desc')
            items = [{
                'id': r.id,
                'name': r.name or '',
                'isbn': getattr(r, 'isbn', '') or '',
                'author': ', '.join(a.name for a in r.author_ids) if hasattr(r, 'author_ids') else '',
                'edition': getattr(r, 'edition', '') or '',
                'media_type': r.media_type_id.name if hasattr(r, 'media_type_id') and r.media_type_id else '',
            } for r in recs]
            return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit})
        except Exception as e:
            _logger.exception('list_media')
            return _error_response(str(e), 500)

    @http.route('/api/library/media', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_media(self, **kw):
        try:
            body = _get_json_body()
            name = (body.get('name') or '').strip()
            if not name:
                return _error_response('Name is required', 400)
            Media = request.env['op.media'].sudo()
            vals = {'name': name}
            if body.get('isbn'):
                vals['isbn'] = body['isbn']
            if body.get('edition'):
                vals['edition'] = body['edition']

            author_names = []
            raw_author = body.get('author')
            if isinstance(raw_author, str) and raw_author.strip():
                author_names = [a.strip() for a in raw_author.split(',') if a.strip()]
            raw_author_ids = body.get('author_ids')
            author_ids = []
            if isinstance(raw_author_ids, (list, tuple)):
                author_ids = [int(a) for a in raw_author_ids if a]
            if author_names and 'author_ids' in Media._fields:
                Author = request.env['op.author'].sudo() if 'op.author' in request.env else None
                if Author is not None:
                    for nm in author_names:
                        existing = Author.search([('name', '=', nm)], limit=1)
                        if not existing:
                            existing = Author.create({'name': nm})
                        author_ids.append(existing.id)
            if author_ids and 'author_ids' in Media._fields:
                vals['author_ids'] = [(6, 0, list(set(author_ids)))]

            rec = Media.create(vals)
            return _json_response({'data': {'id': rec.id, 'name': rec.name}})
        except Exception as e:
            _logger.exception('create_media')
            return _error_response(str(e), 500)

    @http.route('/api/library/media/<int:mid>', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def get_media(self, mid, **kw):
        try:
            rec = request.env['op.media'].sudo().browse(mid)
            if not rec.exists():
                return _error_response('Not found', 404)
            author_names = [a.name for a in rec.author_ids] if hasattr(rec, 'author_ids') else []
            return _json_response({
                'id': rec.id,
                'name': rec.name or '',
                'isbn': getattr(rec, 'isbn', '') or '',
                'edition': getattr(rec, 'edition', '') or '',
                'author_ids': rec.author_ids.ids if hasattr(rec, 'author_ids') else [],
                'author_names': author_names,
                'author': ', '.join(author_names),
                'publisher_ids': rec.publisher_ids.ids if hasattr(rec, 'publisher_ids') else [],
                'media_type': rec.media_type_id.name if hasattr(rec, 'media_type_id') and rec.media_type_id else '',
            })
        except Exception as e:
            return _error_response(str(e), 500)

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

    # ── Movements ────────────────────────────────────────────────────

    @http.route('/api/library/movements', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_movements(self, **kw):
        try:
            M = request.env['op.media.movement'].sudo()
            offset, limit, page = _paginate(kw)
            total = M.search_count([])
            recs = M.search([], offset=offset, limit=limit, order='id desc')
            items = [{
                'id': r.id,
                'media_id': r.media_id.id if r.media_id else 0,
                'media_name': r.media_id.name if r.media_id else '',
                'student_id': r.student_id.id if hasattr(r, 'student_id') and r.student_id else 0,
                'student_name': r.student_id.partner_id.name if hasattr(r, 'student_id') and r.student_id and r.student_id.partner_id else '',
                'faculty_id': r.faculty_id.id if hasattr(r, 'faculty_id') and r.faculty_id else 0,
                'faculty_name': r.faculty_id.partner_id.name if hasattr(r, 'faculty_id') and r.faculty_id and r.faculty_id.partner_id else '',
                'issued_date': str(r.issued_date) if hasattr(r, 'issued_date') and r.issued_date else '',
                'return_date': str(r.return_date) if hasattr(r, 'return_date') and r.return_date else '',
                'state': getattr(r, 'state', 'issue') or 'issue',
            } 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/library/movements', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_movement(self, **kw):
        try:
            body = _get_json_body()
            vals = {}
            if body.get('media_id'):
                vals['media_id'] = int(body['media_id'])
            if body.get('student_id'):
                vals['student_id'] = int(body['student_id'])
            if body.get('faculty_id'):
                vals['faculty_id'] = int(body['faculty_id'])
            rec = request.env['op.media.movement'].sudo().create(vals)
            return _json_response({'data': {'id': rec.id}})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/library/movements/<int:mid>', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False)
    @jwt_required
    def update_movement(self, mid, **kw):
        try:
            rec = request.env['op.media.movement'].sudo().browse(mid)
            if not rec.exists():
                return _error_response('Not found', 404)
            body = _get_json_body()
            vals = {}
            if 'return_date' in body:
                vals['return_date'] = body['return_date']
            if vals:
                rec.write(vals)
            return _json_response({'data': {'id': rec.id}})
        except Exception as e:
            return _error_response(str(e), 500)

    @http.route('/api/library/movements/<int:mid>/return', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def return_movement(self, mid, **kw):
        try:
            rec = request.env['op.media.movement'].sudo().browse(mid)
            if not rec.exists():
                return _error_response('Not found', 404)
            from datetime import date
            rec.write({'return_date': str(date.today()), 'state': 'return'})
            return _json_response({'data': {'id': rec.id}})
        except Exception as e:
            return _error_response(str(e), 500)

    # ── Library Cards ────────────────────────────────────────────────

    @http.route('/api/library/cards', type='http', auth='public', methods=['GET'], csrf=False)
    @jwt_required
    def list_cards(self, **kw):
        try:
            M = request.env['op.library.card'].sudo()
            offset, limit, page = _paginate(kw)
            total = M.search_count([])
            recs = M.search([], offset=offset, limit=limit, order='id desc')
            items = [{
                'id': r.id,
                'number': r.number if hasattr(r, 'number') else str(r.id),
                'student_id': r.student_id.id if hasattr(r, 'student_id') and r.student_id else 0,
                'student_name': r.student_id.partner_id.name if hasattr(r, 'student_id') and r.student_id and r.student_id.partner_id else '',
                'faculty_id': r.faculty_id.id if hasattr(r, 'faculty_id') and r.faculty_id else 0,
                'faculty_name': r.faculty_id.partner_id.name if hasattr(r, 'faculty_id') and r.faculty_id and r.faculty_id.partner_id else '',
            } 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/library/cards', type='http', auth='public', methods=['POST'], csrf=False)
    @jwt_required
    def create_card(self, **kw):
        try:
            body = _get_json_body()
            vals = {}
            if body.get('student_id'):
                vals['student_id'] = int(body['student_id'])
            rec = request.env['op.library.card'].sudo().create(vals)
            return _json_response({'data': {'id': rec.id}})
        except Exception as e:
            return _error_response(str(e), 500)
