"""Platform settings endpoints powering `/admin/settings-platform`.

Exposes three groups:
  * Codes (backed by `encoach.code`)
  * Packages (simple persisted list in `ir.config_parameter`)
  * Grading config (min / max / increment, in `ir.config_parameter`)
"""
import json
import logging
import uuid

from odoo import http, fields as odoo_fields
from odoo.http import request
from odoo.addons.encoach_api.controllers.base import (
    jwt_required, _json_response, _error_response, _get_json_body,
)

_logger = logging.getLogger(__name__)

_PKG_PARAM = 'encoach.platform.packages'
_GRADE_PARAM = 'encoach.platform.grading'
_DEFAULT_PACKAGES = [
    {'id': 1, 'name': 'IELTS Starter',   'price': 99,   'duration': '1 month',  'discount': 0},
    {'id': 2, 'name': 'IELTS Pro',       'price': 249,  'duration': '3 months', 'discount': 15},
    {'id': 3, 'name': 'Corporate Bundle','price': 1999, 'duration': '12 months','discount': 25},
]
_DEFAULT_GRADING = {'min_score': 0, 'max_score': 9, 'increment': 0.5}


def _ser_code(c):
    return {
        'id': c.id,
        'code': c.code or '',
        'code_type': c.code_type or 'individual',
        'user_type': c.user_type or 'student',
        'max_uses': c.max_uses or 1,
        'uses': c.uses or 0,
        'used': bool(c.uses and c.max_uses and c.uses >= c.max_uses),
        'expiry_date': c.expiry_date.isoformat() if c.expiry_date else '',
        'created': c.create_date.isoformat() if c.create_date else '',
        'entity_id': c.entity_id.id if c.entity_id else None,
    }


class PlatformSettingsController(http.Controller):

    # ── Codes ────────────────────────────────────────────────────────────
    @http.route('/api/codes', type='http', auth='public',
                methods=['GET'], csrf=False)
    @jwt_required
    def list_codes(self, **kw):
        try:
            Code = request.env['encoach.code'].sudo()
            domain = []
            ct = kw.get('code_type')
            if ct and ct != 'all':
                domain.append(('code_type', '=', ct))
            used = kw.get('used')
            try:
                size = min(int(kw.get('size') or 100), 500)
            except (TypeError, ValueError):
                size = 100
            recs = Code.search(domain, limit=size, order='id desc')
            items = [_ser_code(c) for c in recs]
            if used in ('true', 'false'):
                want = used == 'true'
                items = [i for i in items if i['used'] == want]
            return _json_response({
                'data': items, 'items': items, 'total': len(items),
            })
        except Exception as e:
            _logger.exception('list_codes')
            return _error_response(str(e), 500)

    @http.route('/api/codes/generate', type='http', auth='public',
                methods=['POST'], csrf=False)
    @jwt_required
    def generate_codes(self, **kw):
        """Body: { count?: int, code_type?: 'individual'|'corporate',
                    user_type?: 'student'|'teacher'|'corporate',
                    max_uses?: int, expiry_date?: ISO-str }"""
        try:
            body = _get_json_body()
            count = max(1, min(int(body.get('count') or 1), 200))
            vals_common = {
                'creator_id': request.env.user.id,
                'code_type':  body.get('code_type') or 'individual',
                'user_type':  body.get('user_type') or 'student',
                'max_uses':   int(body.get('max_uses') or 1),
            }
            if body.get('expiry_date'):
                vals_common['expiry_date'] = body['expiry_date']
            if body.get('entity_id'):
                vals_common['entity_id'] = int(body['entity_id'])

            created = []
            for _ in range(count):
                vals = dict(vals_common, code=uuid.uuid4().hex[:8].upper())
                rec = request.env['encoach.code'].sudo().create(vals)
                created.append(_ser_code(rec))
            return _json_response({'data': created, 'count': len(created)})
        except Exception as e:
            _logger.exception('generate_codes')
            return _error_response(str(e), 500)

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

    # ── Packages (ir.config_parameter JSON blob) ─────────────────────────
    def _read_packages(self):
        Param = request.env['ir.config_parameter'].sudo()
        raw = Param.get_param(_PKG_PARAM)
        if not raw:
            return list(_DEFAULT_PACKAGES)
        try:
            return json.loads(raw)
        except Exception:
            return list(_DEFAULT_PACKAGES)

    def _write_packages(self, packages):
        request.env['ir.config_parameter'].sudo().set_param(
            _PKG_PARAM, json.dumps(packages))

    @http.route('/api/packages', type='http', auth='public',
                methods=['GET'], csrf=False)
    @jwt_required
    def list_packages(self, **kw):
        pkgs = self._read_packages()
        return _json_response({'data': pkgs, 'items': pkgs, 'total': len(pkgs)})

    @http.route('/api/packages', type='http', auth='public',
                methods=['POST'], csrf=False)
    @jwt_required
    def create_package(self, **kw):
        try:
            body = _get_json_body()
            pkgs = self._read_packages()
            next_id = max((p.get('id', 0) for p in pkgs), default=0) + 1
            pkg = {
                'id':       next_id,
                'name':     body.get('name') or f'Package {next_id}',
                'price':    float(body.get('price') or 0),
                'duration': body.get('duration') or '1 month',
                'discount': float(body.get('discount') or 0),
            }
            pkgs.append(pkg)
            self._write_packages(pkgs)
            return _json_response(pkg)
        except Exception as e:
            _logger.exception('create_package')
            return _error_response(str(e), 500)

    @http.route('/api/packages/<int:pid>', type='http', auth='public',
                methods=['PATCH', 'PUT'], csrf=False)
    @jwt_required
    def update_package(self, pid, **kw):
        try:
            body = _get_json_body()
            pkgs = self._read_packages()
            for p in pkgs:
                if p.get('id') == pid:
                    for k in ('name', 'duration'):
                        if k in body:
                            p[k] = body[k]
                    for k in ('price', 'discount'):
                        if k in body:
                            p[k] = float(body[k])
                    self._write_packages(pkgs)
                    return _json_response(p)
            return _error_response('Not found', 404)
        except Exception as e:
            _logger.exception('update_package')
            return _error_response(str(e), 500)

    @http.route('/api/packages/<int:pid>', type='http', auth='public',
                methods=['DELETE'], csrf=False)
    @jwt_required
    def delete_package(self, pid, **kw):
        pkgs = self._read_packages()
        new_pkgs = [p for p in pkgs if p.get('id') != pid]
        self._write_packages(new_pkgs)
        return _json_response({'success': True})

    # ── Grading (ir.config_parameter JSON blob) ───────────────────────────
    @http.route('/api/grading-config', type='http', auth='public',
                methods=['GET'], csrf=False)
    @jwt_required
    def get_grading(self, **kw):
        Param = request.env['ir.config_parameter'].sudo()
        raw = Param.get_param(_GRADE_PARAM)
        try:
            cfg = json.loads(raw) if raw else dict(_DEFAULT_GRADING)
        except Exception:
            cfg = dict(_DEFAULT_GRADING)
        return _json_response({'data': cfg, **cfg})

    @http.route('/api/grading-config', type='http', auth='public',
                methods=['PATCH', 'PUT', 'POST'], csrf=False)
    @jwt_required
    def set_grading(self, **kw):
        try:
            body = _get_json_body()
            Param = request.env['ir.config_parameter'].sudo()
            raw = Param.get_param(_GRADE_PARAM)
            cfg = dict(_DEFAULT_GRADING)
            if raw:
                try:
                    cfg.update(json.loads(raw))
                except Exception:
                    pass
            for k in ('min_score', 'max_score'):
                if k in body:
                    cfg[k] = int(body[k])
            if 'increment' in body:
                cfg['increment'] = float(body['increment'])
            if cfg['min_score'] >= cfg['max_score']:
                return _error_response('min_score must be less than max_score', 400)
            Param.set_param(_GRADE_PARAM, json.dumps(cfg))
            return _json_response({'data': cfg, **cfg})
        except Exception as e:
            _logger.exception('set_grading')
            return _error_response(str(e), 500)
