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

import threading

from odoo import api, fields, models


class EventLeadRequest(models.Model):
    """ Technical model created when a user requests 'leads generation' on an event based on all
    existing event.lead.rules (see event#action_generate_leads).

    As an event can hold a lot of registrations, we use a batch approach with a separate model that
    contains the batching logic method and the field to retain progress.

    To benefit from a background processing, we use a CRON that calls itself with a CRON trigger
    until the batch is completed, which unlinks this technical generation record. """

    _name = "event.lead.request"
    _description = "Event Lead Request"
    _log_access = False
    _rec_name = "event_id"
    _order = "id asc"

    _REGISTRATIONS_BATCH_SIZE = 200

    event_id = fields.Many2one('event.event', required=True, string="Event", ondelete="cascade")
    processed_registration_id = fields.Integer("Processed Registration",
        help="The ID of the last processed event.registration, used to know where to resume.")

    _sql_constraints = [
        ('uniq_event', 'unique(event_id)', 'You can only have one generation request per event at a time.'),
    ]

    @api.model
    def _cron_generate_leads(self, job_limit=100, registrations_batch_size=None):
        """ See class docstring for details.

        :param job_limit: The maximum amount of 'event.lead.request' to process
          Defaults to 100.
        :param registrations_batch_size: The amount of attendees processed at once.
          Defaults to event.lead.request._REGISTRATIONS_BATCH_SIZE """

        # auto-commit except in testing mode
        auto_commit = not getattr(threading.current_thread(), 'testing', False)

        registrations_batch_size = registrations_batch_size or self._REGISTRATIONS_BATCH_SIZE
        generate_requests = self.env['event.lead.request'].search([], limit=job_limit)
        fulfilled_requests = self.env['event.lead.request']
        for generate_request in generate_requests:
            registrations_to_process = self.env['event.registration'].search([
                ('event_id', '=', generate_request.event_id.id),
                ('state', 'not in', ['draft', 'cancel']),
                ('id', '>', generate_request.processed_registration_id)],
                limit=registrations_batch_size,
                order='id asc'
            )

            registrations_to_process._apply_lead_generation_rules()

            if len(registrations_to_process) < registrations_batch_size:
                # done processing
                fulfilled_requests += generate_request
            else:
                # not complete yet, update last processed registration
                generate_request.processed_registration_id = registrations_to_process[-1].id

            if auto_commit:
                # commit after each completed batch/completed request
                # avoids to re-process everything if an issue with one of the requests
                # important as the lead creation process can typically send emails
                # that should not be duped
                self.env.cr.commit()

        if generate_requests - fulfilled_requests:
            # we still have unfinished requests: run the CRON again
            self.env.ref('event_crm.ir_cron_generate_leads')._trigger()

        if fulfilled_requests:
            fulfilled_requests.unlink()
