# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import logging

from trytond.model import sequence_reorder
from trytond.pool import Pool, PoolMeta
from trytond.tools import remove_forbidden_chars
from trytond.tools.email_ import EmailNotValidError, validate_email

from .common import IdentifiersMixin, gid2id, setattr_changed

logger = logging.getLogger(__name__)


class Party(IdentifiersMixin, metaclass=PoolMeta):
    __name__ = 'party.party'

    @classmethod
    def shopify_fields(cls):
        return {
            'id': None,
            'displayName': None,
            'email': None,
            'phone': None,
            'locale': None,
            }

    @classmethod
    def get_from_shopify(cls, shop, customer):
        pool = Pool()
        ContactMechanism = pool.get('party.contact_mechanism')
        Lang = pool.get('ir.lang')
        party = cls.search_shopify_identifier(
            shop, gid2id(customer['id']))
        if not party:
            party = cls()
        setattr_changed(party, 'name', remove_forbidden_chars(
                customer['displayName']))
        if customer['locale']:
            lang = Lang.get(customer['locale'])
        else:
            lang = None
        setattr_changed(party, 'lang', lang)
        contact_mechanisms = list(getattr(party, 'contact_mechanisms', []))
        for types, value in [
                (['email'], customer['email']),
                (['phone', 'mobile'], customer['phone']),
                ]:
            value = remove_forbidden_chars(value)
            if not value:
                continue
            index = len(contact_mechanisms)
            for i, contact_mechanism in enumerate(contact_mechanisms):
                if (contact_mechanism.type in types
                        and not contact_mechanism.address):
                    index = min(i, index)
                    if (contact_mechanism.value_compact
                            == contact_mechanism.format_value_compact(
                                value, contact_mechanism.type)):
                        contact_mechanisms.insert(
                            index,
                            contact_mechanisms.pop(i))
                        break
            else:
                if types[0] == 'email':
                    try:
                        validate_email(value)
                    except EmailNotValidError as e:
                        logger.info("Skip email %s", value, exc_info=e)
                        continue
                contact_mechanisms.insert(index, ContactMechanism(
                        type=types[0], value=value))
        party.contact_mechanisms = sequence_reorder(contact_mechanisms)
        # TODO tax_exempt
        return party

    def get_address_from_shopify(self, shopify_address):
        pool = Pool()
        Address = pool.get('party.address')
        ContactMechanism = pool.get('party.contact_mechanism')
        shopify_values = Address.get_shopify_values(shopify_address)
        for address in self.addresses:
            if address.shopify_values() == shopify_values:
                break
        else:
            address = Address(**shopify_values)
            address.party = self
            address.save()

        contact_mechanisms = list(self.contact_mechanisms)
        if phone := remove_forbidden_chars(shopify_address['phone']):
            index = len(contact_mechanisms)
            for i, contact_mechanism in enumerate(contact_mechanisms):
                if (contact_mechanism.type in ['phone', 'mobile']
                        and contact_mechanism.address == address):
                    index = min(i, index)
                    if (contact_mechanism.value_compact
                            == contact_mechanism.format_value_compact(
                                phone, contact_mechanism.type)):
                        contact_mechanisms.insert(
                            index,
                            contact_mechanisms.pop(i))
                        break
            else:
                contact_mechanisms.insert(index, ContactMechanism(
                        party=self, address=address,
                        type='phone', value=phone))
            ContactMechanism.save(sequence_reorder(
                    contact_mechanisms))
        return address


class Address(metaclass=PoolMeta):
    __name__ = 'party.address'

    @classmethod
    def shopify_fields(cls):
        return {
            'name': None,
            'company': None,
            'address1': None,
            'address2': None,
            'city': None,
            'zip': None,
            'countryCodeV2': None,
            'provinceCode': None,
            'phone': None,
            }

    @classmethod
    def get_shopify_values(self, address):
        pool = Pool()
        Country = pool.get('country.country')
        Subdivision = pool.get('country.subdivision')
        SubdivisionType = pool.get('party.address.subdivision_type')

        values = {}
        values['party_name'] = remove_forbidden_chars(address['name'] or '')
        if address['company']:
            values['attn'] = values['party_name']
            values['party_name'] = remove_forbidden_chars(address['company'])
        else:
            values['attn'] = ''
        values['street'] = '\n'.join(filter(None, [
                    address['address1'], address['address2']]))
        values['city'] = remove_forbidden_chars(address['city'] or '')
        values['postal_code'] = address['zip'] or ''
        if address['countryCodeV2']:
            country, = Country.search([
                    ('code', '=', address['countryCodeV2']),
                    ], limit=1)
            values['country'] = country.id
            if address['provinceCode']:
                subdivision_code = '-'.join(
                    [address['countryCodeV2'], address['provinceCode']])
                subdivision_domain = [
                    ('country', '=', country.id),
                    ('code', 'like', subdivision_code + '%'),
                    ]
                types = SubdivisionType.get_types(country)
                if types:
                    subdivision_domain.append(('type', 'in', types))
                subdivisions = Subdivision.search(subdivision_domain, limit=1)
                if subdivisions:
                    subdivision, = subdivisions
                    values['subdivision'] = subdivision.id
        return values

    def shopify_values(self):
        values = {}
        values['party_name'] = self.party_name or ''
        values['attn'] = self.attn or ''
        values['street'] = self.street or ''
        values['city'] = self.city or ''
        values['postal_code'] = self.postal_code or ''
        if self.country:
            values['country'] = self.country.id
        if self.subdivision:
            values['subdivision'] = self.subdivision.id
        return values


class Replace(metaclass=PoolMeta):
    __name__ = 'party.replace'

    @classmethod
    def fields_to_replace(cls):
        return super().fields_to_replace() + [
            ('web.shop.shopify_identifier', 'record'),
            ]
