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

TAXONOMY_MODELS = {
    'subject': 'encoach.subject',
    'domain': 'encoach.domain',
    'topic': 'encoach.topic',
    'learning_objective': 'encoach.learning.objective',
}

PARENT_FIELD_MAP = {
    'domain': 'subject_id',
    'topic': 'domain_id',
    'learning_objective': 'topic_id',
}


class EncoachTaxonomyController(http.Controller):

    # ------------------------------------------------------------------
    # GET /api/taxonomy/subjects
    # ------------------------------------------------------------------
    @http.route('/api/taxonomy/subjects', type='http', auth='none',
                methods=['GET'], csrf=False)
    @jwt_required
    def get_subjects(self, **kw):
        try:
            Subject = request.env['encoach.subject'].sudo()
            subjects = Subject.search([('active', '=', True)])

            items = []
            for s in subjects:
                items.append({
                    'id': s.id,
                    'name': s.name,
                    'code': s.code or '',
                    'description': s.description or '',
                    'domain_count': len(s.domain_ids),
                })

            return _json_response({'subjects': items})

        except Exception as e:
            _logger.exception('get_subjects failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # GET /api/taxonomy/tree
    # ------------------------------------------------------------------
    @http.route('/api/taxonomy/tree', type='http', auth='none',
                methods=['GET'], csrf=False)
    @jwt_required
    def get_tree(self, **kw):
        try:
            Subject = request.env['encoach.subject'].sudo()
            subjects = Subject.search([('active', '=', True)])

            tree = []
            for s in subjects:
                domains = []
                for d in s.domain_ids:
                    topics = []
                    for t in d.topic_ids:
                        objectives = []
                        for o in t.learning_objective_ids:
                            objectives.append({
                                'id': o.id,
                                'name': o.name,
                                'bloom_level': o.bloom_level or '',
                                'description': o.description or '',
                            })
                        topics.append({
                            'id': t.id,
                            'name': t.name,
                            'description': t.description or '',
                            'learning_objectives': objectives,
                        })
                    domains.append({
                        'id': d.id,
                        'name': d.name,
                        'description': d.description or '',
                        'topics': topics,
                    })
                tree.append({
                    'id': s.id,
                    'name': s.name,
                    'code': s.code or '',
                    'description': s.description or '',
                    'domains': domains,
                })

            return _json_response({'tree': tree})

        except Exception as e:
            _logger.exception('get_tree failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/taxonomy/node
    # ------------------------------------------------------------------
    @http.route('/api/taxonomy/node', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def create_node(self, **kw):
        try:
            body = _get_json_body()
            node_type = body.get('type')
            if not node_type or node_type not in TAXONOMY_MODELS:
                return _error_response(
                    f'type must be one of: {", ".join(TAXONOMY_MODELS.keys())}', 400,
                )

            name = body.get('name')
            if not name:
                return _error_response('name is required', 400)

            model_name = TAXONOMY_MODELS[node_type]
            Model = request.env[model_name].sudo()

            vals = {'name': name}
            if body.get('description'):
                vals['description'] = body['description']

            if node_type == 'subject':
                code = body.get('code')
                if not code:
                    return _error_response('code is required for subjects', 400)
                vals['code'] = code
            else:
                parent_id = body.get('parent_id')
                if not parent_id:
                    parent_field = PARENT_FIELD_MAP[node_type]
                    return _error_response(
                        f'parent_id ({parent_field}) is required for {node_type}', 400,
                    )
                vals[PARENT_FIELD_MAP[node_type]] = int(parent_id)

                if node_type == 'learning_objective' and body.get('bloom_level'):
                    vals['bloom_level'] = body['bloom_level']

            record = Model.create(vals)

            return _json_response({
                'id': record.id,
                'type': node_type,
                'name': record.name,
            }, 201)

        except Exception as e:
            _logger.exception('create_node failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # PUT /api/taxonomy/node/<int:node_id>
    # ------------------------------------------------------------------
    @http.route('/api/taxonomy/node/<int:node_id>', type='http', auth='none',
                methods=['PUT'], csrf=False)
    @jwt_required
    def update_node(self, node_id, **kw):
        try:
            body = _get_json_body()
            node_type = body.get('type')
            if not node_type or node_type not in TAXONOMY_MODELS:
                return _error_response(
                    f'type must be one of: {", ".join(TAXONOMY_MODELS.keys())}', 400,
                )

            model_name = TAXONOMY_MODELS[node_type]
            Model = request.env[model_name].sudo()
            record = Model.browse(node_id)
            if not record.exists():
                return _error_response(f'{node_type} not found', 404)

            vals = {}
            if body.get('name'):
                vals['name'] = body['name']
            if 'description' in body:
                vals['description'] = body.get('description') or ''

            if node_type == 'subject':
                if body.get('code'):
                    vals['code'] = body['code']
                if 'active' in body:
                    vals['active'] = bool(body['active'])
            elif node_type == 'learning_objective' and body.get('bloom_level'):
                vals['bloom_level'] = body['bloom_level']

            if vals:
                record.write(vals)

            return _json_response(record.to_api_dict())

        except Exception as e:
            _logger.exception('update_node failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # DELETE /api/taxonomy/node/<int:node_id>
    # ------------------------------------------------------------------
    @http.route('/api/taxonomy/node/<int:node_id>', type='http', auth='none',
                methods=['DELETE'], csrf=False)
    @jwt_required
    def delete_node(self, node_id, **kw):
        try:
            body = _get_json_body()
            node_type = body.get('type') or kw.get('type')
            if not node_type or node_type not in TAXONOMY_MODELS:
                return _error_response(
                    f'type must be one of: {", ".join(TAXONOMY_MODELS.keys())}', 400,
                )

            model_name = TAXONOMY_MODELS[node_type]
            Model = request.env[model_name].sudo()
            record = Model.browse(node_id)
            if not record.exists():
                return _error_response(f'{node_type} not found', 404)

            record.unlink()
            return _json_response({}, 204)

        except Exception as e:
            _logger.exception('delete_node failed')
            return _error_response(str(e), 500)
