# Copyright 2020 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from datetime import datetime, time

from dateutil.relativedelta import relativedelta
from pytz import UTC, timezone

from odoo import _, api, fields, models


class MailActivity(models.Model):
    _inherit = "mail.activity"

    next_reminder = fields.Datetime(
        string="Next reminder",
        compute="_compute_next_reminder",
        compute_sudo=True,
        store=True,
    )
    last_reminder_local = fields.Datetime(
        string="Last reminder (local)",
    )
    deadline = fields.Datetime(
        compute="_compute_deadline",
        compute_sudo=True,
        store=True,
    )

    @api.model
    def _get_activities_to_remind_domain(self):
        """Hook for extensions"""
        return [
            ("next_reminder", "<=", fields.Datetime.now()),
            ("deadline", ">=", fields.Datetime.now()),
        ]

    @api.model
    def _get_activities_to_remind(self):
        return self.search(self._get_activities_to_remind_domain())

    @api.model
    def _process_reminders(self):
        activities = self._get_activities_to_remind()
        activities.action_remind()
        return activities

    @api.depends(
        "user_id.tz",
        "activity_type_id.reminders",
        "deadline",
        "last_reminder_local",
    )
    def _compute_next_reminder(self):
        now = fields.Datetime.now()
        for activity in self:
            if activity.deadline < now:
                activity.next_reminder = None
                continue
            reminders = activity.activity_type_id._get_reminder_offsets()
            if not reminders:
                activity.next_reminder = None
                continue
            reminders.sort(reverse=True)
            tz = timezone(activity.user_id.sudo().tz or "UTC")
            last_reminder_local = (
                tz.localize(activity.last_reminder_local)
                if activity.last_reminder_local
                else None
            )
            local_deadline = tz.localize(
                datetime.combine(
                    activity.date_deadline,
                    time.min,  # Schedule reminder based of beginning of day
                )
            )
            for reminder in reminders:
                next_reminder_local = local_deadline - relativedelta(
                    days=reminder,
                )
                if not last_reminder_local or next_reminder_local > last_reminder_local:
                    break
            if last_reminder_local and next_reminder_local <= last_reminder_local:
                activity.next_reminder = None
                continue
            activity.next_reminder = next_reminder_local.astimezone(UTC).replace(
                tzinfo=None
            )

    @api.depends("user_id.tz", "date_deadline")
    def _compute_deadline(self):
        for activity in self:
            tz = timezone(activity.user_id.sudo().tz or "UTC")
            activity.deadline = (
                tz.localize(datetime.combine(activity.date_deadline, time.max))
                .astimezone(UTC)
                .replace(tzinfo=None)
            )

    def action_notify(self):
        res = super().action_notify()
        utc_now = fields.Datetime.now().replace(tzinfo=UTC)
        for activity in self:
            if activity.last_reminder_local:
                continue
            tz = timezone(activity.user_id.sudo().tz or "UTC")
            activity.last_reminder_local = utc_now.astimezone(tz).replace(tzinfo=None)
        return res

    def action_remind(self):
        """
        Group reminders by user and type and send them together
        """
        MailThread = self.env["mail.thread"]
        utc_now = fields.Datetime.now().replace(tzinfo=UTC)
        for user in self.mapped("user_id"):
            activities = self.filtered(lambda activity: activity.user_id == user)
            tz = timezone(user.sudo().tz or "UTC")
            local_now = utc_now.astimezone(tz)

            subject = _("Some activities you are assigned too expire soon.")

            body = self.env["ir.qweb"]._render(
                "mail_activity_reminder.message_activity_assigned",
                dict(activities=activities, model_description="Activities"),
                minimal_qcontext=True,
            )
            MailThread.message_notify(
                partner_ids=user.partner_id.ids,
                body=body,
                subject=subject,
                model_description="Activity",
                notif_layout="mail.mail_notification_light",
            )
            activities.update({"last_reminder_local": local_now.replace(tzinfo=None)})
