# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import fields, models


class SmsTracker(models.Model):
    _inherit = "sms.tracker"

    SMS_STATE_TO_TRACE_STATUS = {
        'error': 'error',
        'process': 'process',
        'outgoing': 'outgoing',
        'canceled': 'cancel',
        'pending': 'pending',
        'sent': 'sent',
    }

    mailing_trace_id = fields.Many2one('mailing.trace', ondelete='cascade')

    def _action_update_from_provider_error(self, provider_error):
        error_status, failure_type, failure_reason = super()._action_update_from_provider_error(provider_error)
        self._update_sms_traces(error_status or 'error', failure_type=failure_type, failure_reason=failure_reason)
        return error_status, failure_type, failure_reason

    def _action_update_from_sms_state(self, sms_state, failure_type=False, failure_reason=False):
        super()._action_update_from_sms_state(sms_state, failure_type=failure_type, failure_reason=failure_reason)
        trace_status = self.SMS_STATE_TO_TRACE_STATUS[sms_state]
        traces = self._update_sms_traces(trace_status, failure_type=failure_type, failure_reason=failure_reason)
        self._update_sms_mailings(trace_status, traces)

    def _update_sms_traces(self, trace_status, failure_type=False, failure_reason=False):
        if not self.mailing_trace_id:  # avoid a search below
            return self.env['mailing.trace']
        # See _update_sms_notifications
        statuses_to_ignore = {
            'cancel': ['cancel', 'process', 'pending', 'sent'],
            'outgoing': ['outgoing', 'process', 'pending', 'sent'],
            'process': ['process', 'pending', 'sent'],
            'pending': ['pending', 'sent'],
            'bounce': ['bounce'],
            'sent': ['sent'],
            'error': ['error'],
        }[trace_status]
        traces = self.mailing_trace_id.filtered(lambda t: t.trace_status not in statuses_to_ignore)
        if traces:
            traces_values = {
                'trace_status': trace_status,
                'failure_type': failure_type,
                'failure_reason': failure_reason,
                **{'sent_datetime': fields.Datetime.now() if trace_status == 'pending' else {}},
            }
            traces.write(traces_values)
        return traces

    def _update_sms_mailings(self, trace_status, traces):
        traces.flush_recordset(['trace_status'])

        if trace_status == 'process':
            traces.mass_mailing_id.write({'state': 'sending'})
            return

        mailings_to_mark_done = self.env['mailing.mailing'].search([
            ('id', 'in', traces.mass_mailing_id.ids),
            '!', ('mailing_trace_ids.trace_status', '=', 'process'),  # = not any trace with 'process' status
            ('state', '!=', 'done'),
        ])

        if mailings_to_mark_done:
            if self.env.user.is_public:  # From webhook event
                mailings_to_mark_done._track_set_author(self.env.ref('base.partner_root'))
            for mailing in mailings_to_mark_done:
                mailing.write({
                    'state': 'done',
                    'sent_date': fields.Datetime.now(),
                    'kpi_mail_required': not mailing.sent_date
                })
