# -*- encoding: utf-8 -*-

import logging
from pathlib import Path

from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.core.validators import MaxValueValidator, MinValueValidator

log = logging.getLogger(__name__)


class SavedGuilds(models.Model):
    """
    Represents a saved Discord Guild (aka Server).
    These are shown in the UI on the sidebar, and can be selected
    to see associated Subscriptions.
    """

    id = models.AutoField(primary_key=True)

    # Have to use charfield instead of positiveBigIntegerField due to an Sqlite
    # issue that rounds down the value
    # https://github.com/sequelize/sequelize/issues/9335
    guild_id = models.CharField(
        verbose_name=_("guild id"),
        max_length=128,
        help_text=_("Discord snowflake ID for the represented guild.")
    )

    name = models.CharField(
        max_length=128,
        help_text=_("Name of the represented guild.")
    )

    icon = models.CharField(
        max_length=128,
        help_text=_("Hash for the represented guild's icon.")
    )

    added_by = models.ForeignKey(
        verbose_name=_("added by"),
        to="authentication.DiscordUser",
        on_delete=models.CASCADE,
        help_text=_("The user who added created this instance.")
    )

    permissions = models.CharField(
        max_length=64,
        help_text=_("Guild permissions for the user who added this instance.")
    )

    owner = models.BooleanField(
        default=False,
        help_text=_("Does the 'added by' user own this guild?")
    )

    class Meta:
        """
        Metadata for the SavedGuilds Model.
        """

        verbose_name = "saved guild"
        verbose_name_plural = "saved guilds"
        get_latest_by = "-creation_datetime"

        constraints = [
            # Prevent servers from having subscriptions with duplicate names
            models.UniqueConstraint(
                fields=["added_by", "guild_id"],
                name="unique added_by & guild_id pair"
            )
        ]

    def __str__(self) -> str:
        return self.name


class SubChannel(models.Model):
    """
    Represents a Discord TextChannel, saved against a Subscription.
    SubChannels are used as targets to send content from Subscriptions.
    """

    id = models.AutoField(primary_key=True)

    # Have to use charfield instead of positiveBigIntegerField due to an Sqlite
    # issue that rounds down the value
    # https://github.com/sequelize/sequelize/issues/9335
    channel_id = models.CharField(
        verbose_name=_("channel id"),
        max_length=128,
        help_text=_("Discord snowflake ID for the represented Channel.")
    )

    subscription = models.ForeignKey(
        to="home.Subscription",
        on_delete=models.CASCADE,
        help_text=_("The linked Subscription, must be unique.")
    )

    class Meta:
        """
        Metadata for the SubChannel Model.
        """

        verbose_name = "SubChannel"
        verbose_name_plural = "SubChannels"
        get_latest_by = "id"
        constraints = [
            # Prevent servers from having subscriptions with duplicate names
            models.UniqueConstraint(
                fields=["channel_id", "subscription"],
                name="unique channel id and subscription pair")
        ]

    def __str__(self) -> str:
        return self.channel_id


# using a brilliant matching model design from paperless-ngx src
class Filter(models.Model):
    MATCH_NONE = 0
    MATCH_ANY = 1
    MATCH_ALL = 2
    MATCH_LITERAL = 3
    MATCH_REGEX = 4
    MATCH_FUZZY = 5
    MATCH_AUTO = 6

    MATCHING_ALGORITHMS = (
        (MATCH_NONE, _("None")),
        (MATCH_ANY, _("Any: Item contains any of these words (space separated)")),
        (MATCH_ALL, _("All: Item contains all of these words (space separated)")),
        (MATCH_LITERAL, _("Exact: Item contains this string")),
        (MATCH_REGEX, _("Regular expression: Item matches this regex")),
        (MATCH_FUZZY, _("Fuzzy: Item contains a word similar to this word")),
        # (MATCH_AUTO, _("Automatic")),
    )

    id = models.AutoField(primary_key=True)

    name = models.CharField(_("name"), max_length=128)

    match = models.CharField(_("match"), max_length=256, blank=True)

    matching_algorithm = models.PositiveIntegerField(
        _("matching algorithm"),
        choices=MATCHING_ALGORITHMS,
        default=MATCH_ANY,
    )

    is_insensitive = models.BooleanField(_("is insensitive"), default=True)

    is_whitelist = models.BooleanField(_("is whitelist"), default=False)

    # Have to use charfield instead of positiveBigIntegerField due to an Sqlite
    # issue that rounds down the value
    # https://github.com/sequelize/sequelize/issues/9335
    guild_id = models.CharField(_("guild id"), max_length=128)

    class Meta:
        ordering = ("name",)
        constraints = [
            models.UniqueConstraint(
                fields=["name", "guild_id"],
                name="unique name & guild id pair"
            )
        ]

    def __str__(self):
        return f"{self.guild_id} - {self.name}"


class Subscription(models.Model):
    """
    The Subscription Model.
    'Subscription' in the context of PYRSS is an RSS Feed with various settings.
    """

    id = models.AutoField(primary_key=True)

    name = models.CharField(
        max_length=32,
        null=False,
        blank=False
    )

    url = models.URLField()

    # NOTE:
    # Have to use charfield instead of positiveBigIntegerField due to an Sqlite
    # issue that rounds down the value
    # https://github.com/sequelize/sequelize/issues/9335
    guild_id = models.CharField(
        max_length=128
    )

    creation_datetime = models.DateTimeField(
        default=timezone.now,
        editable=False
    )

    extra_notes = models.CharField(
        max_length=250,
        null=True,
        blank=True,
    )

    filters = models.ManyToManyField(to="home.Filter", blank=True)

    article_title_mutators = models.ManyToManyField(
        to="home.ArticleMutator",
        related_name="title_mutated_subscriptions",
        blank=True,
    )

    article_desc_mutators = models.ManyToManyField(
        to="home.ArticleMutator",
        related_name="desc_mutated_subscriptions",
        blank=True,
    )

    embed_colour = models.CharField(
        max_length=6,
        default="3498db",
        blank=True
    )

    published_threshold = models.DateTimeField(default=timezone.now, blank=True)

    article_fetch_image = models.BooleanField(
        default=True,
        help_text="Will the resulting article have an image?"
    )

    active = models.BooleanField(default=True)

    class Meta:
        """
        Metadata for the Subscription Model.
        """

        verbose_name = "subscription"
        verbose_name_plural = "subscriptions"
        get_latest_by = "-creation_datetime"
        constraints = [
            # Prevent servers from having subscriptions with duplicate names
            models.UniqueConstraint(fields=["name", "guild_id"], name="unique name & server pair")
        ]

    @property
    def channels_count(self) -> int:
        """
        Returns the number of 'SubChannel' objects assocaited
        with this subscription.
        """

        return len(SubChannel.objects.filter(subscription=self))

    def save(self, *args, **kwargs):
        new_text = "New " if self._state.adding else ""
        log.debug("%sSubscription Saved %s", new_text, self.id)
        super().save(*args, **kwargs)

    def __str__(self) -> str:
        return self.name


class TrackedContent(models.Model):
    """
    Tracked Content Model
    'Tracked Content' identifies articles and tracks them being sent.
    This is used to ensure duplicate articles aren't sent in feeds.    
    """

    id = models.AutoField(primary_key=True)

    guid = models.CharField(max_length=256)

    title = models.CharField(max_length=728)

    url = models.URLField()

    subscription = models.ForeignKey(to=Subscription, on_delete=models.CASCADE)

    channel_id = models.CharField(max_length=128)

    message_id = models.CharField(max_length=128)

    blocked = models.BooleanField(default=False)

    creation_datetime = models.DateTimeField(
        default=timezone.now,
        editable=False
    )

    class Meta:

        verbose_name = "tracked content"
        verbose_name = "tracked contents"
        get_latest_by = "-creation_datetime"
        constraints = [
            models.UniqueConstraint(fields=["guid", "channel_id"], name="unique guid & channel_id pair"),
            models.UniqueConstraint(fields=["url", "channel_id"], name="unique url & channel_id pair")
        ]

    def __str__(self) -> str:
        return self.title


class ArticleMutator(models.Model):

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64)
    value = models.CharField(max_length=32)

    def __str__(self) -> str:
        return self.name
