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

from trytond.i18n import lazy_gettext
from trytond.model import fields
from trytond.pool import Pool
from trytond.pyson import Eval


def id2gid(resouce, id):
    return f'gid://shopify/{resouce}/{id}'


def gid2id(gid):
    _, id = gid[len('gid://shopify/'):].split('/', 1)
    return int(id)


class IdentifierMixin:
    __slots__ = ()

    shopify_identifier_signed = fields.Integer(
        lazy_gettext('web_shop_shopify.msg_shopify_identifier'))
    shopify_identifier_signed._sql_type = 'BIGINT'
    shopify_identifier = fields.Function(fields.Integer(
            lazy_gettext('web_shop_shopify.msg_shopify_identifier')),
        'get_shopify_identifier', setter='set_shopify_identifier',
        searcher='search_shopify_identifier')
    shopify_identifier_char = fields.Function(fields.Char(
            lazy_gettext('web_shop_shopify.msg_shopify_identifier')),
        'get_shopify_identifier', setter='set_shopify_identifier',
        searcher='search_shopify_identifier')
    shopify_url = fields.Function(fields.Char(
            lazy_gettext('web_shop_shopify.msg_shopify_url'),
            states={
                'invisible': ~Eval('shopify_url'),
                }),
        'get_shopify_url')

    def get_shopify_identifier(self, name):
        if self.shopify_identifier_signed is not None:
            value = self.shopify_identifier_signed + (1 << 63)
            if name == 'shopify_identifier_char':
                value = str(value)
            return value

    @classmethod
    def set_shopify_identifier(cls, records, name, value):
        if value is not None:
            value = int(value) - (1 << 63)
        cls.write(records, {
                'shopify_identifier_signed': value,
                })

    @classmethod
    def search_shopify_identifier(cls, name, domain):
        _, operator, value = domain
        if operator in {'in', 'not in'}:
            value = [
                int(v) - (1 << 63) if v is not None else None for v in value]
        elif value is not None:
            value = int(value) - (1 << 63)
        return [('shopify_identifier_signed', operator, value)]

    def get_shopify_url(self, name):
        if (getattr(self, 'shopify_resource', None)
                and getattr(self, 'web_shop', None)
                and self.shopify_identifier_char):
            return urljoin(
                self.web_shop.shopify_url,
                f'admin/{self.shopify_resource}/{self.shopify_identifier_char}'
                )

    @classmethod
    def copy(cls, records, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()
        default.setdefault('shopify_identifier_signed')
        return super().copy(records, default=default)


class IdentifiersUpdateMixin:
    __slots__ = ()

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls._shopify_fields = set()

    @classmethod
    def set_shopify_to_update(cls, records):
        pool = Pool()
        Identifier = pool.get('web.shop.shopify_identifier')
        identifiers = cls.get_shopify_identifier_to_update(records)
        Identifier.write(identifiers, {
                'to_update': True,
                })

    @classmethod
    def get_shopify_identifier_to_update(cls, records):
        raise NotImplementedError

    @classmethod
    def on_modification(cls, mode, records, field_names=None):
        super().on_modification(mode, records, field_names=field_names)
        if mode in {'create', 'delete'}:
            cls.set_shopify_to_update(records)
        elif mode == 'write':
            if field_names & cls._shopify_fields:
                cls.set_shopify_to_update(records)


class IdentifiersMixin(IdentifiersUpdateMixin):
    __slots__ = ()

    shopify_identifiers = fields.One2Many(
        'web.shop.shopify_identifier', 'record',
        lazy_gettext('web_shop_shopify.msg_shopify_identifiers'),
        readonly=True)

    def get_shopify_identifier(self, web_shop):
        for record in self.shopify_identifiers:
            if record.web_shop == web_shop:
                return record.shopify_identifier

    def set_shopify_identifier(self, web_shop, identifier=None):
        pool = Pool()
        Identifier = pool.get('web.shop.shopify_identifier')
        for record in self.shopify_identifiers:
            if record.web_shop == web_shop:
                if not identifier:
                    Identifier.delete([record])
                    return
                else:
                    if record.shopify_identifier != identifier:
                        record.shopify_identifier = identifier
                        record.save()
                    return record
        if identifier:
            record = Identifier(record=self, web_shop=web_shop)
            record.shopify_identifier = identifier
            record.save()
            return record

    @classmethod
    def search_shopify_identifier(cls, web_shop, identifier):
        records = cls.search([
                ('shopify_identifiers', 'where', [
                        ('web_shop', '=', web_shop.id),
                        ('shopify_identifier', '=', identifier),
                        ]),
                ])
        if records:
            record, = records
            return record

    def is_shopify_to_update(self, web_shop, **extra):
        for record in self.shopify_identifiers:
            if record.web_shop == web_shop:
                return (record.to_update
                    or (record.to_update_extra or {}) != extra)
        return True

    @classmethod
    def copy(cls, records, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()
        default.setdefault('shopify_identifiers')
        return super().copy(records, default=default)

    @classmethod
    def on_modification(cls, mode, records, field_names=None):
        pool = Pool()
        Identifier = pool.get('web.shop.shopify_identifier')
        super().on_modification(mode, records, field_names=field_names)
        if mode == 'delete':
            Identifier.delete(
                sum((r.shopify_identifiers for r in records), ()))

    @classmethod
    def get_shopify_identifier_to_update(cls, records):
        return sum((list(r.shopify_identifiers) for r in records), [])


def setattr_changed(record, name, value):
    if getattr(record, name, None) != value:
        setattr(record, name, value)
        return True
