import uuid
from datetime import datetime

import tldextract
from django.contrib.auth import get_user_model
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVector, SearchVectorField
from django.db import models
from django.db.models import Q, UniqueConstraint
from model_utils.fields import AutoCreatedField, AutoLastModifiedField
from model_utils.models import TimeStampedModel
from simple_history.models import HistoricalRecords

from verify_trusted.companies.managers import CompanyManager, CompanyQuerySet

User = get_user_model()


def user_directory_path(instance, filename):
    timestr = str(datetime.now().strftime('%Y_%m_%d_%H_%M_%S'))
    new_filename = filename.split(".")
    return (
        'company/{0}_{1}.{2}'.format(
            instance.user.id, timestr, new_filename[len(new_filename) - 1]
        )
        if instance.user
        else 'company/{0}_{1}.{2}'.format(
            instance.id, timestr, new_filename[len(new_filename) - 1]
        )
    )


class Company(TimeStampedModel):
    name = models.CharField(max_length=500, db_index=True)
    first_letter = models.CharField(
        max_length=1,
        db_index=True,
        blank=True,
        null=True,
        help_text='First letter of name',
    )
    category = models.CharField(max_length=550, blank=True, null=True, db_index=True)
    category_main = models.CharField(
        max_length=250, blank=True, null=True, db_index=True
    )
    email = models.TextField(blank=True, null=True)
    phone = models.CharField(max_length=250, blank=True, null=True)
    logo = models.ImageField(
        upload_to=user_directory_path, blank=True, null=True, max_length=500
    )
    url = models.CharField(unique=True, max_length=250, blank=True, null=True)
    normalized_domain = models.CharField(max_length=250, blank=True, null=True)
    status = models.IntegerField(blank=True, null=True, default=None)
    url_display = models.CharField(max_length=250)
    address = models.CharField(max_length=950, blank=True, null=True)
    about = models.TextField(blank=True, null=True)
    reviews_count = models.IntegerField(blank=True, null=True, default=None, db_index=True)
    average_rating = models.FloatField(blank=True, null=True, default=0, db_index=True)
    domain = models.CharField(max_length=500, blank=True, null=True)
    crawled_at = models.DateTimeField(blank=True, null=True)
    last_review_date = models.CharField(max_length=250, blank=True, null=True)
    opening = models.JSONField(blank=True, null=True)
    last_synced_at = models.DateTimeField(blank=True, null=True)
    new_reviews = models.IntegerField(blank=True, null=True)
    owner_ceo = models.CharField(max_length=2425, blank=True, null=True)
    id_business = models.CharField(max_length=33, blank=True, null=True)
    headquarters = models.CharField(max_length=445, blank=True, null=True)
    years_onsite = models.CharField(max_length=45, blank=True, null=True)
    years = models.CharField(max_length=45, blank=True, null=True)
    business_type = models.CharField(max_length=425, blank=True, null=True)
    accreditation = models.CharField(max_length=245, blank=True, null=True)
    other = models.JSONField(blank=True, null=True)
    last_http_status = models.IntegerField(blank=True, null=True)
    user = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='companies', blank=True, null=True
    )
    one_year = models.BooleanField(default=True)
    ssl_status = models.BooleanField(default=True)
    is_verified = models.BooleanField(default=False, db_index=True)
    map = models.JSONField(blank=True, null=True)
    currency_symbol = models.CharField(
        max_length=20, blank=True, null=True, default='USD'
    )
    web_alias=models.CharField(max_length=425, blank=True, null=True)
    country_code = models.CharField(max_length=20, blank=True, null=True)

    # Search
    search_vector = SearchVectorField(
        null=True,
        blank=True,
        editable=False,
    )  # https://docs.djangoproject.com/en/4.0/ref/contrib/postgres/search/#searchvectorfield

    # Histories
    history = HistoricalRecords(
        excluded_fields=[
            'search_vector',
            'first_letter',
            'created',
            'modified',
        ]
    )

    # Custom manager
    # https://docs.djangoproject.com/en/4.0/topics/db/managers/#custom-managers
    objects = CompanyManager.from_queryset(CompanyQuerySet)()

    class Meta:
        verbose_name_plural = 'Companies'
        indexes = [
            GinIndex(
                fields=[
                    'search_vector',
                ]
            ),
        ]

    @staticmethod
    def get_search_vector():
        return SearchVector('name')

    def __str__(self):
        return f'{self.name} {self.url} {self.id}'


class Review(models.Model):
    source = models.ForeignKey(
        'reviews.ReviewSource',
        null=True,
        related_name='reviews',
        on_delete=models.CASCADE,
    )
    author = models.CharField(max_length=255, blank=True, null=True)
    date = models.DateField(blank=True, null=True, db_index=True)
    headline = models.CharField(max_length=2500, blank=True, null=True)
    body = models.TextField(blank=True, null=True)
    rating = models.IntegerField(blank=True, null=True, db_index=True)
    date_parse = models.DateTimeField(blank=True, null=True)
    date_modify = AutoLastModifiedField()
    display_order = models.IntegerField(blank=True, null=True)
    url = models.CharField(max_length=500, blank=True, null=True)
    is_active = models.BooleanField(default=False, blank=True, null=True, db_index=True)
    external_id = models.CharField(
        max_length=120,
        default=None,
        blank=True,
        null=True,
        db_index=True,
    )  # ID from source (e.g: `Yelp`, `bbb.org`, ...)
    history = HistoricalRecords()
    lock_edit = models.BooleanField(default=True, blank=True, null=True)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=['source', 'external_id'],
                name="source__external_id__idx",
                condition=Q(external_id__isnull=False),
            ),
        ]


class SourceSocial(models.Model):
    name = models.CharField(max_length=50)
    url = models.CharField(max_length=255, null=True, blank=True)
    logo = models.CharField(max_length=255, null=True, blank=True)
    display_order = models.IntegerField(null=True, blank=True)

    class Meta:
        verbose_name_plural = 'Source Social'


class Social(models.Model):
    url = models.CharField(max_length=255, null=True, blank=True)
    company = models.ForeignKey(
        Company,
        on_delete=models.CASCADE,
        related_name='socials',
        null=True,
        blank=True,
    )
    source = models.ForeignKey(SourceSocial, on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = 'Socials'


class Plan(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True)
    cost = models.FloatField(blank=True, null=True)
    price = models.FloatField(default=9.99)
    pack = models.IntegerField(default=30)
    currency = models.CharField(max_length=20, null=True, blank=True)
    is_active = models.BooleanField(default=True)


class Payment(models.Model):
    class Status(models.TextChoices):
        CANCEL = 'CANCEL'
        FAILED = 'FAILED'
        COMPLETE = 'COMPLETE'
        PENDING = 'PENDING'
        DRAFT = 'DRAFT'

    id = models.UUIDField(
        primary_key=True, unique=True, default=uuid.uuid4, editable=False
    )
    stripe_id = models.CharField(max_length=255, null=True, blank=True)
    stripe_customer_id = models.CharField(max_length=255, null=True, blank=True)
    stripe_subscription_id = models.CharField(max_length=255, null=True, blank=True)
    stripe_payment_method_id = models.CharField(max_length=255, null=True, blank=True)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    description = models.CharField(max_length=500, null=True, blank=True)
    currency = models.CharField(max_length=20, null=True, blank=True)
    plan = models.ForeignKey(Plan, on_delete=models.CASCADE)
    address = models.CharField(max_length=500, null=True, blank=True)
    country = models.CharField(max_length=100, null=True, blank=True)
    city = models.CharField(max_length=100, null=True, blank=True)
    zip_code = models.CharField(max_length=100, null=True, blank=True)
    status = models.CharField(
        max_length=50,
        choices=Status.choices,
        default=Status.DRAFT,
        null=True,
        blank=True,
    )
    stripe_status = models.CharField(max_length=50, null=True, blank=True)
    stripe_url = models.CharField(max_length=500, null=True, blank=True)
    price_to_usd = models.FloatField(null=True, blank=True)
    create_date = AutoCreatedField()
    modify_date = AutoLastModifiedField()
    vat = models.FloatField(null=True, blank=True)
    total_amount = models.FloatField(null=True, blank=True)


class Subscription(models.Model):
    company = models.OneToOneField(
        Company,
        on_delete=models.CASCADE,
        primary_key=True,
        related_name='subscriptions',
    )
    payment = models.ForeignKey(
        Payment, on_delete=models.CASCADE, null=True, blank=True
    )
    due_date = models.DateField()
    create_date = AutoCreatedField()
