import random
import string

from django.contrib.postgres.fields import ArrayField
from django.db import models

from apps.authentication.models import Organization, City, Province, BankAccountInformation
from apps.authorization.models import UserRelations
from apps.core.models import BaseModel
from apps.product.models import Product, Broker, QuotaBrokerValue, QuotaDistribution, OrganizationQuotaStats


class ProviderCompany(BaseModel):
    user_relation = models.ForeignKey(
        UserRelations,
        related_name='pos_provider',
        on_delete=models.CASCADE,
        null=True,
    )
    name_fa = models.CharField(max_length=250, null=True)
    name_en = models.CharField(max_length=250, null=True)
    activation = models.BooleanField(default=False)

    class Meta:
        unique_together = ('user_relation', 'name_fa')

    def __str__(self):
        return f'Payment Company: {self.name_fa}-{self.id}'

    def save(self, *args, **kwargs):
        return super(ProviderCompany, self).save(*args, **kwargs)


class Device(BaseModel):
    device_identity = models.CharField(max_length=25, null=True)
    acceptor = models.CharField(max_length=50, null=True)
    terminal = models.CharField(max_length=50, null=True)
    mac = models.CharField(max_length=50, null=True)
    serial = models.TextField(null=True, unique=True)
    password = models.CharField(max_length=25, null=True)
    multi_device = models.BooleanField(default=False)
    server_in = models.BooleanField(default=False)
    latitude = models.FloatField(default=0)
    longitude = models.FloatField(default=0)
    is_activated = models.BooleanField(default=False)
    pre_registered = models.BooleanField(default=False)
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='devices',
        null=True
    )
    assigned_state = models.BooleanField(default=False)

    def __str__(self):
        return f'Device: {self.serial} - {self.id}'

    def generate_device_identity(self):  # noqa
        """ generate identity for every device """
        # prefix = "POS"
        while True:
            number_part = ''.join(random.choices(string.digits, k=9))
            code = f"{number_part}"
            if not Device.objects.filter(device_identity=code).exists():
                return code

    def save(self, *args, **kwargs):
        if not self.device_identity:
            self.device_identity = self.generate_device_identity()
        return super(Device, self).save(*args, **kwargs)


class BankAccountDeviceLink(BaseModel):
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='bank_account_device_links',
        null=True
    )
    bank_account = models.ForeignKey(
        BankAccountInformation,
        on_delete=models.CASCADE,
        related_name='linked_devices',
        null=True
    )
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='linked_bank_accounts',
        null=True
    )

    def __str__(self):
        return (f'{self.id} --> organization: {self.organization.name}/'
                f'{self.organization.id} --> device: {self.device.serial}')

    def save(self, *args, **kwargs):
        return super(BankAccountDeviceLink, self).save(*args, **kwargs)


class DeviceActivationCode(BaseModel):
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name="code",
        null=True
    )
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='device_activations',
        null=True
    )
    code = models.CharField(max_length=10, null=True, unique=True)
    expires_at = models.DateTimeField(auto_now_add=True)
    is_used = models.BooleanField(default=False)

    def __str__(self):
        return f'Device: {self.device.serial} - code: {self.code}'

    def save(self, *args, **kwargs):
        return super(DeviceActivationCode, self).save(*args, **kwargs)


class DeviceVersion(BaseModel):
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='devices_version',
        null=True
    )
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='device_versions',
        null=True
    )
    name = models.CharField(max_length=250, null=True)
    code = models.IntegerField(default=0)
    description = models.TextField(null=True)
    enable = models.BooleanField(default=True)
    remove = models.BooleanField(default=False)
    url = models.TextField(null=True, blank=True, max_length=2000)
    checksum = models.CharField(max_length=350, null=True)

    def __str__(self):
        return f'Version: {self.name}-{self.device.serial}'

    def save(self, *args, **kwargs):
        return super(DeviceVersion, self).save(*args, **kwargs)


class Sessions(BaseModel):
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='devices',
        null=True
    )
    name = models.CharField(max_length=250, null=True)
    password = models.CharField(max_length=25, null=True)
    version = models.IntegerField(default=0, null=True)
    mac = models.CharField(max_length=50, null=True)
    ip = models.CharField(max_length=15, default='0.0.0.0')
    sdk = models.TextField(null=True)
    serial = models.TextField(null=True)
    latitude = models.FloatField(default=0, null=True)
    longitude = models.FloatField(default=0, null=True)

    def __str__(self):
        return f'Session: {self.name}-{self.version}-{self.id}'

    def save(self, *args, **kwargs):
        return super(Sessions, self).save(*args, **kwargs)


class POSClient(BaseModel):
    name = models.CharField(max_length=255, null=True)
    client_type = models.CharField(max_length=25, choices=[
        ('business', 'صنف'),
        ('person', 'شخص آزاد'),  # noqa
        ('organization', 'سازمان')  # noqa
    ])
    is_organization = models.BooleanField(default=False)
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='client',
        null=True
    )

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

    def save(self, *args, **kwargs):
        return super(POSClient, self).save(*args, **kwargs)


class POSClientAttribute(BaseModel):
    client_type = models.CharField(max_length=25, choices=[
        ('business', 'صنف'),
        ('person', 'شخص آزاد'),  # noqa
        ('organization', 'سازمان')  # noqa
    ], null=True)
    key = models.CharField(max_length=100, null=True)
    label = models.CharField(max_length=255, null=True)
    field_type = models.CharField(max_length=20, choices=[
        ('text', 'متن'),
        ('number', 'عدد'),
        ('date', 'تاریخ'),  # noqa
        ('choice', 'چند کزینه ای'),  # noqa
    ], null=True)
    required = models.BooleanField(default=False)
    choices = ArrayField(base_field=models.CharField(max_length=150), null=True, blank=True)
    custom_field = models.BooleanField(default=False)

    def __str__(self):
        return f'attribute: {self.key}-{self.field_type}'

    def save(self, *args, **kwargs):
        return super(POSClientAttribute, self).save(*args, **kwargs)


class POSClientAttributeValue(BaseModel):
    client = models.ForeignKey(
        POSClient,
        on_delete=models.CASCADE,
        related_name='attribute_values',
        null=True
    )
    attribute = models.ForeignKey(
        POSClientAttribute,
        on_delete=models.CASCADE,
        related_name='attribute_values',
        null=True
    )
    value = models.TextField(null=True)

    def __str__(self):
        return f'Client Attribute: {self.client.name}-{self.attribute.key}'

    def save(self, *args, **kwargs):
        return super(POSClientAttributeValue, self).save(*args, **kwargs)


class DeviceAssignment(BaseModel):
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='device_assignments',
        null=True
    )
    client = models.ForeignKey(
        POSClient,
        on_delete=models.CASCADE,
        related_name='assignment',
        null=True
    )
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='assignment',
        null=True
    )

    def __str__(self):
        return f'Device: {self.device.serial} - Client: {self.client.name}'

    def save(self, *args, **kwargs):
        return super(DeviceAssignment, self).save(*args, **kwargs)


class StakeHolders(BaseModel):
    assignment = models.ForeignKey(
        DeviceAssignment,
        on_delete=models.CASCADE,
        related_name='stake_holders',
        null=True
    )
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='stake_holders',
        null=True
    )
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='pos_stake_holders',
        null=True
    )
    HOLDER_TYPES = (
        ('organization', 'ORGANIZATION'),
        ('company', 'COMPANY'),
    )
    stake_holder_type = models.CharField(
        max_length=150,
        choices=HOLDER_TYPES,
        default='organization'
    )
    broker = models.ForeignKey(
        Broker,
        on_delete=models.CASCADE,
        related_name='pos_stake_holders',
        null=True
    )
    default = models.BooleanField(default=False)

    def __str__(self):
        return f'ID: {self.id}-Device: {self.assignment.device.serial}-organization: {self.organization.name}'

    def save(self, *args, **kwargs):
        return super(StakeHolders, self).save(*args, **kwargs)


class StakeHolderShareAmount(BaseModel):
    quota_distribution = models.ForeignKey(
        QuotaDistribution,
        on_delete=models.CASCADE,
        related_name='holders_share_amount',
        null=True
    )
    org_quota_stat = models.ForeignKey(
        OrganizationQuotaStats,
        on_delete=models.CASCADE,
        related_name='holders_share_amount',
        null=True
    )
    stakeholders = models.ForeignKey(
        StakeHolders,
        on_delete=models.CASCADE,
        related_name='holders_share_amount',
        null=True
    )
    share_amount = models.PositiveBigIntegerField(default=0)
    registering_organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='holders_share_amount',
        null=True
    )

    def save(self, *args, **kwargs):
        return super(StakeHolderShareAmount, self).save(*args, **kwargs)


class POSFreeProducts(BaseModel):
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='pos_free_products',
        null=True
    )
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name='free_products',
        null=True
    )
    device = models.ForeignKey(
        Device,
        on_delete=models.CASCADE,
        related_name='free_products',
        null=True
    )
    balance = models.PositiveIntegerField(default=0)
    price = models.PositiveIntegerField(default=0)
    company_fee = models.IntegerField(default=0)

    def __str__(self):
        return f'{self.product.name}-{self.organization.name}'

    def save(self, *args, **kwargs):
        return super(POSFreeProducts, self).save(*args, **kwargs)
