# -*- coding: utf-8 -*-

from dateutil.relativedelta import relativedelta

from odoo import fields, models, _
from odoo.fields import Datetime


class MarketingTrace(models.Model):
    _name = 'marketing.trace'
    _description = 'Marketing Trace'
    _order = 'schedule_date DESC'
    _rec_name = 'participant_id'

    participant_id = fields.Many2one(
        'marketing.participant', string='Participant',
        index=True, ondelete='cascade', required=True)
    res_id = fields.Integer(string='Document ID', related='participant_id.res_id', index=True, store=True, readonly=False)
    is_test = fields.Boolean(string='Test Trace', related='participant_id.is_test', index=True, store=True, readonly=True)
    activity_id = fields.Many2one(
        'marketing.activity', string='Activity',
        index=True, ondelete='cascade', required=True)
    activity_type = fields.Selection(related='activity_id.activity_type', readonly=True)
    trigger_type = fields.Selection(related='activity_id.trigger_type', readonly=True)

    state = fields.Selection([
        ('scheduled', 'Scheduled'),
        ('processed', 'Processed'),
        ('rejected', 'Rejected'),
        ('canceled', 'Canceled'),
        ('error', 'Error')
        ], default='scheduled', index=True, required=True)
    schedule_date = fields.Datetime()
    state_msg = fields.Char(string='Error message')
    # hierarchy
    parent_id = fields.Many2one('marketing.trace', string='Parent', index=True, ondelete='cascade')
    child_ids = fields.One2many('marketing.trace', 'parent_id', string='Direct child traces')
    # statistics
    mailing_trace_ids = fields.One2many('mailing.trace', 'marketing_trace_id', string='Mass mailing statistics')
    sent = fields.Datetime(related='mailing_trace_ids.sent', readonly=False)
    exception = fields.Datetime(related='mailing_trace_ids.exception', readonly=False)
    opened = fields.Datetime(related='mailing_trace_ids.opened', readonly=False)
    replied = fields.Datetime(related='mailing_trace_ids.replied', readonly=False)
    bounced = fields.Datetime(related='mailing_trace_ids.bounced', readonly=False)
    clicked = fields.Datetime(related='mailing_trace_ids.clicked', readonly=False)

    def participant_action_cancel(self):
        self.action_cancel(message=_('Manually'))

    def action_cancel(self, message=None):
        values = {'state': 'canceled', 'schedule_date': Datetime.now()}
        if message:
            values['state_msg'] = message
        self.write(values)
        self.mapped('participant_id').check_completed()

    def action_execute(self):
        self.activity_id.execute_on_traces(self)

    def process_event(self, action):
        """Process event coming from customers currently centered on email actions.
        It updates child traces :

         * opposite actions are canceled, for example mail_not_open when mail_open is triggered;
         * bounced mail cancel all child actions not being mail_bounced;

        :param string action: see trigger_type field of activity
        """
        self.ensure_one()
        if self.participant_id.campaign_id.state not in ['draft', 'running']:
            return

        now = Datetime.from_string(Datetime.now())
        msg = {
            'mail_not_reply': _('Parent activity mail replied'),
            'mail_not_click': _('Parent activity mail clicked'),
            'mail_not_open': _('Parent activity mail opened'),
            'mail_bounce': _('Parent activity mail bounced'),
        }

        opened_child = self.child_ids.filtered(lambda trace: trace.state == 'scheduled')

        for next_trace in opened_child.filtered(lambda trace: trace.activity_id.trigger_type == action):
            if next_trace.activity_id.interval_number == 0:
                next_trace.write({
                    'schedule_date': now,
                })
                next_trace.activity_id.execute_on_traces(next_trace)
            else:
                next_trace.write({
                    'schedule_date': now + relativedelta(**{
                        next_trace.activity_id.interval_type: next_trace.activity_id.interval_number
                    }),
                })

        if action in ['mail_reply', 'mail_click', 'mail_open']:
            opposite_trigger = action.replace('_', '_not_')
            opened_child.filtered(
                lambda trace: trace.activity_id.trigger_type == opposite_trigger
            ).action_cancel(message=msg[opposite_trigger])

        elif action == 'mail_bounce':
            opened_child.filtered(
                lambda trace: trace.activity_id.trigger_type != 'mail_bounce'
            ).action_cancel(message=msg[action])

        return True
