#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program.  If not, see
# <https://www.gnu.org/licenses/>.
#
import logging
import warnings
from collections import OrderedDict

from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _

from pretix.base.signals import (
    register_sales_channel_types, register_sales_channels,
)

logger = logging.getLogger(__name__)
_ALL_CHANNEL_TYPES = None


class SalesChannelType:
    def __repr__(self):
        return '<SalesChannelType: {}>'.format(self.identifier)

    @property
    def identifier(self) -> str:
        """
        The internal identifier of this sales channel type.
        """
        raise NotImplementedError()  # NOQA

    @property
    def verbose_name(self) -> str:
        """
        A human-readable name of this sales channel type.
        """
        raise NotImplementedError()  # NOQA

    @property
    def description(self) -> str:
        """
        A human-readable description of this sales channel type.
        """
        return ""

    @property
    def icon(self) -> str:
        """
        This can be:

        - The name of a Font Awesome icon to represent this channel type.
        - The name of a SVG icon file that is resolvable through the static file system. We recommend to design for a size of 18x14 pixels.
        """
        return "circle"

    @property
    def default_created(self) -> bool:
        """
        Indication, if a sales channel of this type should automatically be created for every organizer
        """
        return True

    @property
    def multiple_allowed(self) -> bool:
        """
        Indication, if multiple sales channels of this type may exist in the same organizer
        """
        return False

    @property
    def testmode_supported(self) -> bool:
        """
        Indication, if a sales channel of this type supports test mode orders
        """
        return True

    @property
    def payment_restrictions_supported(self) -> bool:
        """
        If this property is ``True``, organizers can restrict the usage of payment providers to this sales channel type.

        Example: pretixPOS provides its own sales channel type, ignores the configured payment providers completely and
        handles payments locally. Therefore, this property should be set to ``False`` for the pretixPOS sales channel as
        the event organizer cannot restrict the usage of any payment provider through the backend.
        """
        return True

    @property
    def unlimited_items_per_order(self) -> bool:
        """
        If this property is ``True``, purchases made using sales channels of this type are not limited to the maximum
        amount of items defined in the event settings.
        """
        return False

    @property
    def customer_accounts_supported(self) -> bool:
        """
        If this property is ``True``, checkout will show the customer login step.
        """
        return True

    @property
    def discounts_supported(self) -> bool:
        """
        If this property is ``True``, this sales channel can be selected for automatic discounts.
        """
        return True

    @property
    def required_event_plugin(self) -> str:
        """
        Name of an event plugin that is required for this sales channel to be useful. Defaults to ``None``.
        """
        return


def get_all_sales_channel_types():
    from pretix.base.signals import register_sales_channel_types
    global _ALL_CHANNEL_TYPES

    if _ALL_CHANNEL_TYPES:
        return _ALL_CHANNEL_TYPES

    channels = []
    for recv, ret in register_sales_channel_types.send(None):
        if isinstance(ret, (list, tuple)):
            channels += ret
        else:
            channels.append(ret)
    for recv, ret in register_sales_channels.send(None):  # todo: remove me
        if isinstance(ret, (list, tuple)):
            channels += ret
        else:
            channels.append(ret)
    channels.sort(key=lambda c: c.identifier)
    _ALL_CHANNEL_TYPES = OrderedDict([(c.identifier, c) for c in channels])
    if 'web' in _ALL_CHANNEL_TYPES:
        _ALL_CHANNEL_TYPES.move_to_end('web', last=False)
    return _ALL_CHANNEL_TYPES


def get_all_sales_channels():
    # TODO: remove me
    warnings.warn('Using get_all_sales_channels() is no longer appropriate, use get_al_sales_channel_types() instead.',
                  DeprecationWarning, stacklevel=2)
    return get_all_sales_channel_types()


class WebshopSalesChannelType(SalesChannelType):
    identifier = "web"
    verbose_name = _('Online shop')
    icon = "globe"


class ApiSalesChannelType(SalesChannelType):
    identifier = "api"
    verbose_name = _('API')
    description = _('API sales channels come with no built-in functionality, but may be used for custom integrations.')
    icon = "exchange"
    default_created = False
    multiple_allowed = True


SalesChannel = SalesChannelType  # TODO: remove me


@receiver(register_sales_channel_types, dispatch_uid="base_register_default_sales_channel_types")
def base_sales_channels(sender, **kwargs):
    return (
        WebshopSalesChannelType(),
        ApiSalesChannelType(),
    )
