from odoo import models
from odoo.addons.phone_validation.tools import phone_validation


class BaseModel(models.AbstractModel):
    _inherit = 'base'

    def _sms_get_recipients_info(self, force_field=False, partner_fallback=True):
        """ Get SMS recipient information on current record set. This method
        checks for numbers and sanitation in order to centralize computation.

        Example of use cases

          * click on a field -> number is actually forced from field, find customer
            linked to record, force its number to field or fallback on customer fields;
          * contact -> find numbers from all possible phone fields on record, find
            customer, force its number to found field number or fallback on customer fields;

        :param force_field: either give a specific field to find phone number, either
            generic heuristic is used to find one based on :meth:`_phone_get_number_fields`;
        :param partner_fallback: if no value found in the record, check its customer
            values based on :meth:`_mail_get_partners`;

        :rtype: dict[int, dict[str, Any]]
        :return: a dictionnary with the following structure:

            .. code-block:: python

                {
                    record.id: {
                        # a res.partner recordset that is the customer (void or
                        # singleton) linked to the recipient.
                        # See _mail_get_partners;
                        'partner': ...,

                        # sanitized number to use (coming from record's field
                        # or partner's phone fields). Set to False if number
                        # impossible to parse and format;
                        'sanitized': ...,

                        # original number before sanitation;
                        'number': ...,

                        # whether the number comes from the customer phone
                        # fields. If False it means number comes from the
                        # record itself, even if linked to a customer;
                        'partner_store': ...,

                        # field in which the number has been found (generally
                        # mobile or phone, see _phone_get_number_fields);
                        'field_store': ...,
                    }
                    for record in self
                }

        """
        result = dict.fromkeys(self.ids, False)
        tocheck_fields = [force_field] if force_field else self._phone_get_number_fields()
        for record in self:
            all_numbers = [record[fname] for fname in tocheck_fields if fname in record]
            all_partners = record._mail_get_partners()[record.id]

            valid_number, fname = False, False
            for fname in [f for f in tocheck_fields if f in record]:
                valid_number = record._phone_format(fname=fname)
                if valid_number:
                    break

            if valid_number:
                result[record.id] = {
                    'partner': all_partners[0] if all_partners else self.env['res.partner'],
                    'sanitized': valid_number,
                    'number': record[fname],
                    'partner_store': False,
                    'field_store': fname,
                }
            elif all_partners and partner_fallback:
                partner = self.env['res.partner']
                for partner in all_partners:
                    for fname in self.env['res.partner']._phone_get_number_fields():
                        valid_number = partner._phone_format(fname=fname)
                        if valid_number:
                            break

                if not valid_number:
                    fname = 'phone'

                result[record.id] = {
                    'partner': partner,
                    'sanitized': valid_number if valid_number else False,
                    'number': partner[fname],
                    'partner_store': True,
                    'field_store': fname,
                }
            else:
                # did not find any sanitized number -> take first set value as fallback;
                # if none, just assign False to the first available number field
                value, fname = next(
                    ((value, fname) for value, fname in zip(all_numbers, tocheck_fields) if value),
                    (False, tocheck_fields[0] if tocheck_fields else False)
                )
                result[record.id] = {
                    'partner': self.env['res.partner'],
                    'sanitized': False,
                    'number': value,
                    'partner_store': False,
                    'field_store': fname
                }
        return result
