# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import pytz
import uuid

from odoo.tools import consteq
from odoo import _, api, fields, models
from odoo.addons.base.models.res_partner import _tz_get
from odoo.exceptions import UserError
from odoo.addons.bus.models.bus_presence import AWAY_TIMER, DISCONNECTION_TIMER


class MailGuest(models.Model):
    _name = 'mail.guest'
    _description = "Guest"
    _inherit = ['avatar.mixin']
    _avatar_name_field = "name"
    _cookie_name = 'dgid'
    _cookie_separator = '|'

    @api.model
    def _lang_get(self):
        return self.env['res.lang'].get_installed()

    name = fields.Char(string="Name", required=True)
    access_token = fields.Char(string="Access Token", default=lambda self: str(uuid.uuid4()), groups='base.group_system', required=True, readonly=True, copy=False)
    country_id = fields.Many2one(string="Country", comodel_name='res.country')
    lang = fields.Selection(string="Language", selection=_lang_get)
    timezone = fields.Selection(string="Timezone", selection=_tz_get)
    channel_ids = fields.Many2many(string="Channels", comodel_name='mail.channel', relation='mail_channel_member', column1='guest_id', column2='channel_id', copy=False)
    im_status = fields.Char('IM Status', compute='_compute_im_status')

    def _compute_im_status(self):
        self.env.cr.execute("""
            SELECT
                guest_id as id,
                CASE WHEN age(now() AT TIME ZONE 'UTC', last_poll) > interval %s THEN 'offline'
                     WHEN age(now() AT TIME ZONE 'UTC', last_presence) > interval %s THEN 'away'
                     ELSE 'online'
                END as status
            FROM bus_presence
            WHERE guest_id IN %s
        """, ("%s seconds" % DISCONNECTION_TIMER, "%s seconds" % AWAY_TIMER, tuple(self.ids)))
        res = dict(((status['id'], status['status']) for status in self.env.cr.dictfetchall()))
        for guest in self:
            guest.im_status = res.get(guest.id, 'offline')

    def _get_guest_from_context(self):
        """Returns the current guest record from the context, if applicable."""
        guest = self.env.context.get('guest')
        if isinstance(guest, self.pool['mail.guest']):
            return guest
        return self.env['mail.guest']

    def _get_guest_from_request(self, request):
        parts = request.httprequest.cookies.get(self._cookie_name, '').split(self._cookie_separator)
        if len(parts) != 2:
            return self.env['mail.guest']
        guest_id, guest_access_token = parts
        if not guest_id or not guest_access_token:
            return self.env['mail.guest']
        guest = self.env['mail.guest'].browse(int(guest_id)).sudo().exists()
        if not guest or not guest.access_token or not consteq(guest.access_token, guest_access_token):
            return self.env['mail.guest']
        if not guest.timezone:
            timezone = self._get_timezone_from_request(request)
            if timezone:
                guest._update_timezone(timezone)
        return guest.sudo(False).with_context(guest=guest)

    def _get_timezone_from_request(self, request):
        timezone = request.httprequest.cookies.get('tz')
        return timezone if timezone in pytz.all_timezones else False

    def _update_name(self, name):
        self.ensure_one()
        name = name.strip()
        if len(name) < 1:
            raise UserError(_("Guest's name cannot be empty."))
        if len(name) > 512:
            raise UserError(_("Guest's name is too long."))
        self.name = name
        guest_data = {
            'id': self.id,
            'name': self.name
        }
        bus_notifs = [(channel, 'mail.guest/insert', guest_data) for channel in self.channel_ids]
        bus_notifs.append((self, 'mail.guest/insert', guest_data))
        self.env['bus.bus']._sendmany(bus_notifs)

    def _update_timezone(self, timezone):
        query = """
            UPDATE mail_guest
            SET timezone = %s
            WHERE id IN (
                SELECT id FROM mail_guest WHERE id = %s
                FOR NO KEY UPDATE SKIP LOCKED
            )
        """
        self.env.cr.execute(query, (timezone, self.id))

    def _init_messaging(self):
        self.ensure_one()
        partner_root = self.env.ref('base.partner_root')
        return {
            'channels': self.channel_ids.channel_info(),
            'companyName': self.env.company.name,
            'currentGuest': {
                'id': self.id,
                'name': self.name,
            },
            'current_partner': False,
            'current_user_id': False,
            'current_user_settings': False,
            'hasLinkPreviewFeature': self.env['mail.link.preview']._is_link_preview_enabled(),
            'menu_id': False,
            'needaction_inbox_counter': False,
            'partner_root': {
                'id': partner_root.id,
                'name': partner_root.name,
            },
            'shortcodes': [],
            'starred_counter': False,
        }

    def _guest_format(self, fields=None):
        if not fields:
            fields = {'id': True, 'name': True, 'im_status': True}
        guests_formatted_data = {}
        for guest in self:
            data = {}
            if 'id' in fields:
                data['id'] = guest.id
            if 'name' in fields:
                data['name'] = guest.name
            if 'im_status' in fields:
                data['im_status'] = guest.im_status
            guests_formatted_data[guest] = data
        return guests_formatted_data
