import string
import random
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.contrib.auth.models import User, Group
from django.conf import settings
from datetime import datetime, timezone, time, timedelta
from django.utils import timezone

import uuid


# مدل پایه که تمامی مدل ها در سیستم ازین مدل ارث بری می کنند
from general_urls import base_user_gate_way_id


class BaseModel(models.Model):
    key = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    create_date = models.DateTimeField(auto_now_add=True)
    modify_date = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name="%(class)s_createdby",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    modified_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="%(class)s_modifiedby",
        null=True,
        blank=True,
    )
    trash = models.BooleanField(default=False)

    class Meta:
        abstract = True


# مدل استان  برای ذخیره استان استفاده میشود
class Province(BaseModel):
    name = models.CharField(max_length=200, null=True)
    province_id_key = models.IntegerField(null=True)
    province_number = models.IntegerField(default=0)
    province_name = models.CharField(max_length=100, null=True)

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


# مدل شهرستان برای ذخیره شهرستان استفاده میشود
class City(BaseModel):
    province = models.ForeignKey(
        Province, on_delete=models.CASCADE, related_name="city_province", null=True
    )
    province_id_foreign_key = models.IntegerField(null=True)
    city_id_key = models.IntegerField(null=True)
    name = models.CharField(max_length=200, null=True)
    product_price = models.FloatField(default=0)
    province_center = models.BooleanField(default=False)
    city_number = models.IntegerField(default=0)
    city_name = models.CharField(max_length=100, null=True)
    province_number = models.IntegerField(default=0)
    province_name = models.CharField(max_length=100, null=True)

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


# مدل زیربخش شهرستان برای ذخیره زیربخش شهرستان استفاده میشود
class CityUnit(BaseModel):
    city = models.ForeignKey(
        City, on_delete=models.CASCADE, related_name="city_province", null=True
    )
    city_id_foreign_key = models.IntegerField(null=True)
    city_unit_id_key = models.IntegerField(null=True)
    name = models.CharField(max_length=200, null=True)
    city_number = models.IntegerField(default=0)
    city_name = models.CharField(max_length=100, null=True)
    province_number = models.IntegerField(default=0)
    province_name = models.CharField(max_length=100, null=True)

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


class PermissionLevel(BaseModel):
    role = models.ForeignKey(
        Group,
        on_delete=models.CASCADE,
        null=True,
        related_name='group_permission'
    )
    name = models.CharField(max_length=100, null=True)

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


# مدل آدرس  برای ذخیره آدرس استفاده میشود
class SystemAddress(BaseModel):
    province = models.ForeignKey(
        Province,
        on_delete=models.CASCADE,
        related_name="province_address",
        null=True
    )
    city = models.ForeignKey(
        City,
        on_delete=models.CASCADE,
        related_name="city_address",
        null=True
    )
    province_id_foreign_key = models.IntegerField(null=True)
    city_id_foreign_key = models.IntegerField(null=True)
    address_id_key = models.IntegerField(null=True)
    address = models.CharField(max_length=300, null=True)
    postal_code = models.CharField(max_length=20, default="", null=True)
    breeding_unique_id = models.CharField(max_length=50, null=True)
    phone = models.CharField(max_length=20, default="", null=True)
    phone_type = models.CharField(max_length=20, default="", null=True)
    no = models.CharField(max_length=5, default="", null=True)
    floor = models.IntegerField(default=0, null=True)
    unit = models.IntegerField(default=0, null=True)
    city_number = models.IntegerField(default=0)
    city_name = models.CharField(max_length=100, null=True)
    province_number = models.IntegerField(default=0)
    province_name = models.CharField(max_length=100, null=True)

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


# مدل آدرس  برای ذخیره آدرس استفاده میشود
class Address(BaseModel):
    title = models.CharField(max_length=200, default="", null=True)
    country = models.CharField(max_length=100, default="", null=True)
    province = models.CharField(max_length=50, default="", null=True)
    city = models.CharField(max_length=50, default="", null=True)
    address = models.CharField(max_length=300, null=True)
    postal_code = models.CharField(max_length=20, default="", null=True)
    breeding_unique_id = models.CharField(max_length=50, null=True)
    phone = models.CharField(max_length=20, default="", null=True)
    phone_type = models.CharField(max_length=20, default="", null=True)
    no = models.CharField(max_length=5, default="", null=True)
    floor = models.IntegerField(default=0, null=True)
    unit = models.IntegerField(default=0, null=True)

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


# مدل اطلاعات بانکی برای ذخیره اطلاعات جساب شخص استفاده میشود
class BankCard(BaseModel):
    name_of_bank_user = models.CharField(max_length=200, null=True)
    bank_name = models.CharField(max_length=30, null=True)
    card = models.CharField(max_length=16, null=True)
    shaba = models.CharField(max_length=100, null=True)
    account = models.CharField(max_length=50, null=True)
    user_bank_id_key = models.IntegerField(null=True)
    province_name = models.CharField(max_length=50, null=True)

    # state = models.CharField(max_length=30, null=True)


class MultiRole(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="multi_role_users", null=True
    )
    address = models.ForeignKey(
        Address,
        on_delete=models.CASCADE,
        related_name='multi_role_address',
        null=True
    )

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


# مدل پروفایل کاربری برای ذخیره پروفایل کاربری شخص استفاده میشود
class SystemUserProfile(BaseModel):
    token = models.CharField(max_length=36, null=True)
    user_gate_way_id = models.CharField(max_length=6,null=True, unique=True)

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="system_user_profile_user", null=True
    )
    province = models.ForeignKey(
        Province,
        on_delete=models.CASCADE,
        related_name='user_province',
        null=True
    )

    city = models.ForeignKey(
        City,
        on_delete=models.CASCADE,
        related_name='user_city',
        null=True
    )

    user_django_id_foreign_key = models.IntegerField(null=True)
    province_id_foreign_key = models.IntegerField(null=True)
    city_id_foreign_key = models.IntegerField(null=True)
    system_user_profile_id_key = models.IntegerField(null=True)
    fullname = models.CharField(max_length=150, null=True)
    first_name = models.CharField(max_length=200, null=True)
    last_name = models.CharField(max_length=200, null=True)
    father_name = models.CharField(max_length=200, null=True)
    gender = models.CharField(max_length=20, null=True)
    is_alive = models.BooleanField(null=True)
    national_code = models.CharField(max_length=20, null=True)
    national_code_image = models.CharField(max_length=500, null=True)
    national_id = models.CharField(max_length=20, null=True)
    mobile = models.CharField(max_length=11, null=True)
    birthday = models.CharField(max_length=20, null=True)
    image = models.CharField(max_length=500, null=True)
    password = models.CharField(max_length=100, null=True)
    active = models.BooleanField(default=True)
    state = models.JSONField(
        default={
            "province": "",
            "city": "",
            "first_name": "",
            "last_name": "",
            "national_code": "",
            "national_id": "",
            "mobile": "",
            "birthday": "",
            "image": ""
        }
    )
    access_level = models.ManyToManyField(
        PermissionLevel,
        related_name="user_permission_level"
    )
    role = models.ManyToManyField(
        Group,
        related_name='user_system_roles'
    )
    base_order = models.BigIntegerField(null=True)
    city_number = models.IntegerField(default=0)
    city_name = models.CharField(max_length=100, null=True)
    province_number = models.IntegerField(default=0)
    province_name = models.CharField(max_length=100, null=True)
    unit_name = models.CharField(max_length=500, null=True)
    unit_national_id = models.CharField(max_length=100, null=True)
    unit_registration_number = models.CharField(max_length=100, null=True)
    unit_economical_number = models.CharField(max_length=100, null=True)
    unit_province = models.CharField(max_length=100, null=True)
    unit_city = models.CharField(max_length=100, null=True)
    unit_postal_code = models.CharField(max_length=100, null=True)
    unit_address = models.TextField(null=True)
    pos = models.BooleanField(default=True)

    def save(self, *args, **kwargs):
        if self.user_gate_way_id is None:
            while (True):
                res = ''.join(random.choices(string.ascii_lowercase + string.digits, k=5))
                res = base_user_gate_way_id + res
                if not SystemUserProfile.objects.filter(user_gate_way_id=res).exists():
                    break
            self.user_gate_way_id=res
        super(SystemUserProfile, self).save(*args, **kwargs)


# مدل پروفایل کاربری برای ذخیره پروفایل کاربری شخص استفاده میشود
class UserProfile(BaseModel):
    key = models.UUIDField(default=uuid.uuid4, editable=True, null=True)
    token = models.CharField(max_length=36, default="")
    app_token = models.CharField(max_length=36, null=True)
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="users", null=True
    )
    company = models.CharField(max_length=30, null=True)
    address = models.ForeignKey(
        Address,
        on_delete=models.CASCADE,
        related_name='user_address',
        null=True
    )
    role = models.ForeignKey(
        Group,
        on_delete=models.CASCADE,
        null=True,
        related_name='user_role'
    )
    user_bank_info = models.ForeignKey(
        BankCard,
        on_delete=models.CASCADE,
        related_name="bank_user",
        null=True
    )
    fullname = models.CharField(max_length=150, null=True, default="")
    first_name = models.CharField(max_length=200, null=True, default="")
    last_name = models.CharField(max_length=200, null=True, default="")
    natinal_id = models.CharField(max_length=10, null=True, default="")
    mobile = models.CharField(max_length=11, null=True, default="")
    birthday = models.CharField(max_length=20, null=True, default="")
    image = models.CharField(max_length=500, null=True)
    state = models.CharField(max_length=20, default="register")
    unit_name = models.CharField(max_length=100, null=True)
    password = models.CharField(max_length=100, null=True)
    gis_code = models.CharField(max_length=30, null=True)
    operating_licence_capacity = models.BigIntegerField(default=0)
    number_of_halls = models.IntegerField(default=0)
    tenant = models.BooleanField(null=True)
    person_type = models.CharField(max_length=10, null=True)
    economic_code = models.CharField(max_length=30, null=True)
    system_code = models.CharField(max_length=20, null=True)
    epidemiological_code = models.CharField(max_length=20, null=True)
    breeding_unique_id = models.CharField(max_length=20, null=True)
    total_capacity = models.BigIntegerField(default=0)
    licence_number = models.CharField(max_length=20, null=True)
    health_certificate_number = models.CharField(max_length=20, null=True)
    number_of_requests = models.BigIntegerField(default=0)
    hatching_date = models.DateTimeField(default=timezone.now())
    last_party_date = models.DateTimeField(default=timezone.now())
    number_of_incubators = models.BigIntegerField(default=0)
    herd_age_by_day = models.IntegerField(default=0)
    herd_age_by_week = models.IntegerField(default=0)
    number_of_party = models.IntegerField(default=0)
    communication_type = models.CharField(max_length=30, null=True)
    cooperative = models.CharField(max_length=50, null=True)
    date_of_register = models.DateTimeField(default=timezone.now())
    unit_status = models.CharField(max_length=20, null=True)
    samasat_user_code = models.CharField(max_length=20, null=True)
    base_order = models.BigIntegerField(null=True)
    incubation_date = models.DateTimeField(null=True)

    def save(self, *args, **kwargs):
        # if self.first_name != None and self.last_name != None:
        #     self.fullname = self.first_name + " " + self.last_name
        super(UserProfile, self).save(*args, **kwargs)


# مدل نقاط جغرافیایی برای ذخیره نقاط طولی و عرضی آدرس استفاده میشود
class GeoPoint(BaseModel):
    userprofile = models.ForeignKey(
        UserProfile,
        on_delete=models.CASCADE,
        related_name="geo_user",
        null=True
    )
    name = models.CharField(max_length=100, null=True)
    lang = models.CharField(max_length=50, null=True)
    lat = models.CharField(max_length=50, null=True)


class Tenant(BaseModel):
    userprofile = models.ManyToManyField(
        UserProfile,
        related_name="tenant_user",
    )
    fullname = models.CharField(max_length=50, null=True)
    national_code = models.CharField(max_length=20, null=True)
    birthday = models.CharField(max_length=50, null=True)
    rental = models.CharField(max_length=30, null=True)
    tracking_code = models.CharField(max_length=30, null=True)
    rent_date_from = models.CharField(max_length=30, null=True)
    rent_date_to = models.CharField(max_length=30, null=True)


class UserMessageType(BaseModel):
    message_types = (
        ("user", "USER"),
        ("alluser", "AllUSER"),
        ("group", "GROUP"),
        ("allgroup", "AllGROUP"),
        ("usergroup", "UserGroup"),
        ("province_accept", "ProvinceAccept"),
        ("province_rejected", "ProvinceRejected"),
        ("city_operator_accept", "CityOperatorAccept"),
        ("city_operator_rejected", "CityOperatorRejected"),
        ("assignment_accepted", "AssignmentAccepted"),
        ("assignment_rejected", "AssignmentRejected"),
    )
    name = models.CharField(choices=message_types, max_length=50, default="", null=True)

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

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

    pass


# مدل پیام کاربر برای ذخیره پیام کاربر استفاده میشود
class UserMessage(BaseModel):
    roles = models.ManyToManyField(
        Group,
        blank=True,
        related_name="user_roles"
    )
    users = models.ManyToManyField(
        SystemUserProfile,
        blank=True,
        related_name="user_message"
    )
    sender = models.ForeignKey(
        SystemUserProfile,
        on_delete=models.CASCADE,
        related_name="message_sender",
        null=True
    )
    heading = models.CharField(max_length=100, null=True, default="")
    message = models.TextField(max_length=500, null=True, default="")
    link_text = models.CharField(max_length=150, null=True)
    link = models.CharField(max_length=100, null=True)
    image = models.JSONField(default=dict, null=True)
    expire = models.DateTimeField(default=datetime.now() + timedelta(hours=1))
    time = models.DateTimeField(default=datetime.now())
    state = models.CharField(max_length=20, default="pending")
    message_type = models.ForeignKey(
        UserMessageType,
        on_delete=models.CASCADE,
        null=True,
        related_name="message_type"
    )
    message_level = models.CharField(max_length=50, null=True)

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


class SendingMessageMethod(BaseModel):
    level = models.CharField(max_length=50, null=True)
    methods = models.CharField(max_length=150, null=True)

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


class Log(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="log_user", null=True
    )
    function_name = models.CharField(max_length=200, null=True)
    duration = models.FloatField(null=True)
    status = models.IntegerField(null=True)
    response = models.TextField(null=True)
    request = models.TextField(null=True)
    request_body = models.TextField(null=True)
    response_body = models.TextField(null=True)

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


class ExternalTransaction(BaseModel):
    date = models.DateTimeField(auto_now_add=True)
    amount = models.BigIntegerField(default=0)
    amount_with_tax = models.BigIntegerField(default=0)
    status = models.CharField(max_length=100, default='pending')
    transaction_type = models.CharField(max_length=100, null=True)
    type = models.CharField(max_length=100, null=True)
    payer = models.CharField(max_length=100, null=True)
    description = models.CharField(max_length=200, default=False)
    is_complete = models.BooleanField(default=False)
    message = models.TextField(null=True)
    saleReferenceId = models.CharField(max_length=100, null=True)
    refId = models.CharField(max_length=100, null=True)
    orderId = models.CharField(max_length=100, null=True)
    cardHolderPan = models.CharField(max_length=100, null=True)
    receiver_role = models.CharField(max_length=100, null=True)
    creator_role = models.CharField(max_length=100, null=True)
    kill_house_user = models.ForeignKey(
        SystemUserProfile,
        on_delete=models.CASCADE,
        null=True,
        related_name="transaction_kill_house_user"
    )
    chain_company_user = models.ForeignKey(
        SystemUserProfile,
        on_delete=models.CASCADE,
        null=True,
        related_name="transaction_chain_company_user"
    )
    receiver = models.ForeignKey(
        SystemUserProfile,
        on_delete=models.CASCADE,
        null=True,
        related_name="receiver_user"
    )
    creator = models.ForeignKey(
        SystemUserProfile,
        on_delete=models.CASCADE,
        null=True,
        related_name="creator_user"
    )
    union_share = models.BigIntegerField(default=0)
    company_share = models.BigIntegerField(default=0)
    guilds_share = models.BigIntegerField(default=0)
    city_share = models.BigIntegerField(default=0)
    wallet_share = models.BigIntegerField(default=0)
    other_share = models.BigIntegerField(default=0)
    pay_type = models.CharField(max_length=200, null=True)
    temporary_trash = models.BooleanField(default=False)
    temporary_deleted = models.BooleanField(default=False)


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


class UserMessageSend(BaseModel):
    user = models.ForeignKey(SystemUserProfile, on_delete=models.CASCADE, null=True)
    message = models.TextField(null=True)
    receive_code = models.CharField(max_length=400, null=True)

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


class Notice(BaseModel):
    title = models.CharField(max_length=1000, null=True)
    text = models.TextField(null=True)
    users = models.JSONField(null=True)
    read_users = models.JSONField(null=True)
    unread_users = models.JSONField(null=True)
    images = models.JSONField(null=True)
    roles = models.JSONField(null=True)

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


class UserNoticeInfo(BaseModel):
    notice = models.ForeignKey(
        Notice,
        related_name="user_notice",

        on_delete=models.CASCADE,
        null=True
    )
    user = models.ForeignKey(
        SystemUserProfile,
        related_name="notice_users",
        on_delete=models.CASCADE,
        null=True
    )
    seen = models.BooleanField(default=False)

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