import logging

from psycopg2 import IntegrityError

from odoo import _, fields, http
from odoo.http import request

_logger = logging.getLogger(__name__)


class MailQuickTemplateController(http.Controller):
    """JSON-RPC endpoints backing the chatter template picker (Section 10.2).

    Controllers only parse input, call model methods and format output. All
    record-rule security (company isolation, group restriction, active filter)
    is enforced by the ORM exactly as in the UI — no bypass is possible.
    """

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------
    def _user_group_ids(self):
        return set(request.env.user.all_group_ids.ids)

    def _is_template_visible(self, template, user_group_ids):
        """BR-14/BR-15: a template restricted to groups is only visible to a
        user belonging to at least one of those groups."""
        if not template.group_ids:
            return True
        return bool(set(template.group_ids.ids) & user_group_ids)

    # ------------------------------------------------------------------
    # Controller 1: get templates for the picker
    # ------------------------------------------------------------------
    @http.route('/do_mail_quick_templates/get', type='jsonrpc', auth='user')
    def get_templates(self, res_model=None, res_id=None, **kwargs):
        env = request.env
        Template = env['mail.quick.template']

        # Feature flag (per-company) — Section 2.9 / EC-04.
        if not Template._is_feature_enabled():
            return {'categories': [], 'enabled': False}

        # EC-03: silently ignore an uninstalled / unknown model.
        model_for_domain = res_model if res_model and res_model in env else False

        domain = [
            ('active', '=', True),
            '|', ('is_global', '=', True),
                 ('model', '=', model_for_domain or '__none__'),
        ]
        templates = Template.search(domain)

        user_group_ids = self._user_group_ids()
        templates = templates.filtered(
            lambda t: self._is_template_visible(t, user_group_ids)
        )

        # Favorites for the current user, single query (Section 15.3).
        fav_template_ids = set(env['mail.quick.template.favorite'].search([
            ('user_id', '=', env.user.id),
            ('template_id', 'in', templates.ids),
        ]).mapped('template_id').ids)

        # Group by category, ordered by category.sequence then use_count/name.
        categories = {}
        for tmpl in templates:
            cat = tmpl.category_id
            cat_key = cat.id or 0
            if cat_key not in categories:
                categories[cat_key] = {
                    'id': cat.id or 0,
                    'name': cat.name or _('Other'),
                    'sequence': cat.sequence if cat else 9999,
                    'templates': [],
                }
            categories[cat_key]['templates'].append({
                'id': tmpl.id,
                'name': tmpl.name,
                'preview_text': tmpl.preview_text or '',
                'is_favorite': tmpl.id in fav_template_ids,
                'attachment_count': len(tmpl.attachment_ids),
                'is_global': tmpl.is_global,
            })

        # Categories ordered by sequence then name. Templates within each
        # category keep the search order (use_count DESC, then name ASC), which
        # is exactly the ordering required by Section 2.3.
        ordered = sorted(categories.values(), key=lambda c: (c['sequence'], c['name']))
        return {'categories': ordered, 'enabled': True}

    # ------------------------------------------------------------------
    # Controller 2: resolve a template preview
    # ------------------------------------------------------------------
    @http.route('/do_mail_quick_templates/preview', type='jsonrpc', auth='user')
    def preview_template(self, template_id=None, res_model=None, res_id=None, **kwargs):
        env = request.env
        try:
            template = env['mail.quick.template'].browse(int(template_id))
            # Read access enforces record rules (company/active).
            template.check_access('read')
            user_group_ids = self._user_group_ids()
            if not self._is_template_visible(template, user_group_ids):
                return {'resolved_html': '', 'attachment_names': [],
                        'error': _('You are not allowed to use this template.')}
            resolved = template._resolve_placeholders(res_model, res_id)
            return {
                'resolved_html': resolved,
                'attachment_names': template.attachment_ids.mapped('name'),
                'error': None,
            }
        except Exception as exc:  # noqa: BLE001 — never leak a stack trace.
            _logger.warning("Template preview failed: %s", exc)
            return {'resolved_html': '', 'attachment_names': [],
                    'error': _('Could not load the template preview.')}

    # ------------------------------------------------------------------
    # Controller 3: log a template use (fire-and-forget)
    # ------------------------------------------------------------------
    @http.route('/do_mail_quick_templates/log_use', type='jsonrpc', auth='user')
    def log_use(self, template_id=None, res_model=None, res_id=None, **kwargs):
        env = request.env
        try:
            template = env['mail.quick.template'].browse(int(template_id))
            template.check_access('read')
            now = fields.Datetime.now()
            # The log is created with sudo (scoped strictly to this one create)
            # because Template Users have create-only access via this path.
            env['mail.quick.template.log'].sudo().create({
                'template_id': template.id,
                'template_name': template.name,
                'user_id': env.user.id,
                'used_date': now,
                'res_model': res_model or '',
                'res_id': int(res_id) if res_id else 0,
                'company_id': env.company.id,
            })
            template.sudo().write({'last_used_date': now})
            return {'success': True}
        except Exception as exc:  # noqa: BLE001 — never block the insert.
            _logger.warning("Template usage logging failed: %s", exc)
            return {'success': False}

    # ------------------------------------------------------------------
    # Controller 4: copy default attachments for the inserted message
    # ------------------------------------------------------------------
    @http.route('/do_mail_quick_templates/copy_attachments', type='jsonrpc', auth='user')
    def copy_attachments(self, template_id=None, res_model=None, res_id=None, **kwargs):
        """Duplicate the template's default attachments so deleting a message
        attachment never affects the template originals (Section 2.8)."""
        env = request.env
        try:
            template = env['mail.quick.template'].browse(int(template_id))
            template.check_access('read')
            result = []
            for att in template.attachment_ids:
                copy = att.sudo().copy(default={
                    'res_model': res_model or 'mail.compose.message',
                    'res_id': int(res_id) if res_id else 0,
                })
                result.append({
                    'id': copy.id,
                    'name': copy.name,
                    'mimetype': copy.mimetype,
                })
            return {'attachments': result}
        except Exception as exc:  # noqa: BLE001
            _logger.warning("Template attachment copy failed: %s", exc)
            return {'attachments': []}

    # ------------------------------------------------------------------
    # Controller 5: toggle favorite
    # ------------------------------------------------------------------
    @http.route('/do_mail_quick_templates/toggle_favorite', type='jsonrpc', auth='user')
    def toggle_favorite(self, template_id=None, **kwargs):
        env = request.env
        Favorite = env['mail.quick.template.favorite']
        try:
            tid = int(template_id)
            existing = Favorite.search([
                ('user_id', '=', env.user.id),
                ('template_id', '=', tid),
            ], limit=1)
            if existing:
                existing.unlink()
                return {'is_favorite': False}
            try:
                Favorite.create({
                    'user_id': env.user.id,
                    'template_id': tid,
                })
            except IntegrityError:
                # BR-19: a concurrent rapid click already created the favorite.
                env.cr.rollback()
            return {'is_favorite': True}
        except Exception as exc:  # noqa: BLE001
            _logger.warning("Toggle favorite failed: %s", exc)
            # Report current state so the client can reconcile.
            current = Favorite.search_count([
                ('user_id', '=', env.user.id),
                ('template_id', '=', int(template_id)),
            ]) if template_id else 0
            return {'is_favorite': bool(current)}
