from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin, Group
from django.db import models
from django.utils.translation import gettext_lazy as _
import random
from datetime import datetime, timedelta
from django.utils import timezone
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken, OutstandingToken
import hashlib
from django.contrib import admin
from django.conf import settings
import requests
class UserManager(BaseUserManager):
    def create_user(self, phone, password=None):
        if not phone:
            raise ValueError('Users must have a phone number')

        user = self.model(
            phone=phone,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, phone, password=None):
        user = self.create_user(
            phone=phone,
        )
        user.is_staff = True
        user.is_superuser = True
        
        user.set_password(password)
        user.save(using=self._db)
        return user


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=255, verbose_name='ایمیل', blank=True, null=True)
    phone = models.CharField(max_length=12, verbose_name='شماره تماس', unique=True)
    first_name = models.CharField(max_length=50, blank=True, verbose_name='نام')
    last_name = models.CharField(max_length=50, blank=True, verbose_name='نام خانوادگی')
    profile_photo = models.ImageField(upload_to='profile_photos/', null=True, blank=True, verbose_name='عکس پروفایل')
    is_active = models.BooleanField(default=True, verbose_name='فعال بودن کاربر')
    is_staff = models.BooleanField(default=False, verbose_name='کارمند')
    gender_option = (
        ('مرد', 'مرد'),
        ('زن', 'زن')
    )
    gender = models.CharField(choices=gender_option, max_length=20, verbose_name='جنسیت')
    birth_date = models.DateField(blank=True, null=True)
    date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
    otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف')
    otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف')
    video_uploader = models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش')
    objects = UserManager()

    USERNAME_FIELD = 'phone'
    REQUIRED_FIELDS = []

    # @property
    # def groups(self):
    #     return None


    def generate_special_code(self):
        """Generate and save a unique special code for the user if missing."""
        # simple deterministic code based on phone and timestamp hash
        base = f"{self.phone}-{timezone.now().timestamp()}"
        code = hashlib.sha256(base.encode()).hexdigest()[:12].upper()

        return code

    @property
    def full_name(self):
        if self.first_name and self.last_name:
            return f"{self.first_name} {self.last_name}"
        return None

    # @property
    # def user_permissions(self):
    #     return None

    class Meta:
        verbose_name = 'کاربر'
        verbose_name_plural = 'کاربران'

    def _hash_otp(self, otp):
        return hashlib.sha256(otp.encode()).hexdigest()

    def set_otp(self):
        raw_otp = str(random.randint(100000, 999999))
        self.otp_hash = self._hash_otp(raw_otp)
        self.otp_expiry = timezone.now() + timedelta(minutes=5)
        self.save()
        return raw_otp

    def clear_otp(self):
        self.otp_hash = None
        self.otp_expiry = None
        self.save()

    def verify_otp(self, otp_code):
        if self.otp_hash and self.otp_expiry > timezone.now():
            return self.otp_hash == self._hash_otp(otp_code)
        return False




    def blacklist_user_tokens(self):
        try:
            tokens = OutstandingToken.objects.filter(user=self)
            for token in tokens:
                BlacklistedToken.objects.get_or_create(token=token)
        except Exception as e:
            print(f"block list error: {e}")


    def __str__(self):
        if self.first_name and self.last_name:
            return f'{self.first_name} {self.last_name}'
        else:
            return self.phone

    def get_name(self):
        if self.first_name and self.last_name:
            return f'{self.first_name} {self.last_name}'
        else:
            return self.phone


class SpecialDiscountCode(models.Model):
    user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='spital_code')
    code = models.CharField(max_length=12, unique=True)

    def __str__(self):
        return f'{self.user} - {self.code}'



class ShopModel(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='shop', verbose_name='کاربر')
    shop_name = models.CharField(max_length=100, verbose_name='نام فروشگاه')
    shop_description = models.TextField(verbose_name='توضیحات فروشگاه')
    commission_percent = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='درصد کمیسیون')
    telegram_chat_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='شناسه چت تلگرام', help_text='برای ارسال خودکار فاکتورها به تلگرام')

    customer_pickup_title = models.CharField(max_length=40, verbose_name='عنوان دریافت حضوری', blank=True, null=True)
    customer_pickup_description = models.CharField(max_length=500, verbose_name='توضیحات دریافت حضوری', blank=True, null=True)


    def __str__(self):
        return f"{self.user.phone} - {self.shop_name}"
    
    class Meta:
        verbose_name = 'فروشگاه'
        verbose_name_plural = 'فروشگاه ها'


class UserAddressModel(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address', verbose_name='کاربر')
    name = models.CharField(max_length=30, verbose_name='نام ادرس')
    address = models.TextField(verbose_name='ادرس کامل')
    postal_code = models.CharField(max_length=10, verbose_name='کد پستی')
    phone = models.CharField(max_length=11, verbose_name='شماره تماس برای ارسال', help_text='شماره تماس کاربر و شماره ی ارسالی میتواند متفاوت باشد')
    city = models.CharField(max_length=30, verbose_name='شهر')
    province = models.CharField(max_length=30, verbose_name='استان')
    for_me = models.BooleanField(default=False, verbose_name='برای خود کاربر')
    is_main = models.BooleanField(default=False, verbose_name='ادرس اصلی کاربر')

    def __str__(self):
        return f"{self.user.phone}, {self.name}"
    
    class Meta:
        verbose_name = 'ادرس کاربر'
        verbose_name_plural = 'ادرس های کاربر'


import os
import json
from pywebpush import webpush, WebPushException

class PushSubscription(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    endpoint = models.TextField(unique=True)
    keys = models.JSONField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.user} push'
    
    class Meta:
        verbose_name = 'اشتراک نوتیفیکیشن'
        verbose_name_plural = 'اشتراک های نوتیفیکیشن'

    def send_notif(self, title, body, icon):
        payload = {
            "title": 'فروشگاه هی ملز',
            "body": body,
            "icon": 'https://api.heymlz.com' + icon,
            "image": 'https://api.heymlz.com' + icon,
        }
        print(payload)
        try:
            webpush(
                subscription_info={
                    "endpoint": self.endpoint,
                    "keys": self.keys
                },
                data=json.dumps(payload),
                vapid_private_key=settings.VAPID_PRIVATE_KEY,
                vapid_claims={
                    "sub": "mailto:admin@example.com"
                }
            )
        except WebPushException as ex:
            print("Failed to send notification:", ex)
    
    @classmethod
    def send_group_notification(cls, user, title, body):
        payload = {
            "title": 'فروشگاه هی ملز',
            "body": body,
            "icon": '' 
        }

        subscriptions = PushSubscription.objects.filter(user=user)
        for sub in subscriptions:
            try:
                webpush(
                    subscription_info={
                        "endpoint": sub.endpoint,
                        "keys": sub.keys
                    },
                    data=json.dumps(payload),
                    vapid_private_key=settings.VAPID_PRIVATE_KEY,
                    vapid_claims={
                        "sub": "mailto:admin@example.com",
                        'aud': 'https://mamalizz-cooked.vercel.app'
                    }
                )
            except WebPushException as ex:
                print(f"Failed to send notification to {sub.user}:", ex)



class NotifBaseModel(models.Model):
    title = models.CharField(max_length=50)
    content = models.TextField()
    image = models.ImageField()
    created_at = models.DateTimeField(auto_now_add=True)
    is_read = models.BooleanField(default=False)

    class Meta:
        abstract = True
        
    def __str__(self):
        return self.title

class NewsModel(NotifBaseModel):

    def notif_type(self):
        return 'NEWS'


class UserNotificationModel(NotifBaseModel):
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def notif_type(self):
        return 'USER_NOTIF'


def get_location_from_ip(ip_address):
    try:
        response = requests.get(f"http://ip-api.com/json/{ip_address}")
        data = response.json()
        if data["status"] == "success":
            return data['country'], data['regionName'], data['city'], data.get('zip', 'ناموجود'), data['lat'], data['lon'], data['isp']
        else:
            print("Error fetching data: ", data["message"])
            return None
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

class SecurityBreachAttemptModel(models.Model):
    ip_address = models.CharField(max_length=100, verbose_name="آدرس آی‌پی")
    country = models.CharField(max_length=101, verbose_name="کشور", blank=True, null=True)
    region_name = models.CharField(max_length=102, verbose_name="منطقه", blank=True, null=True)
    city = models.CharField(max_length=103, verbose_name="شهر", blank=True, null=True)
    zip_code = models.CharField(max_length=104, verbose_name="کد پستی", blank=True, null=True)
    lon = models.CharField(max_length=105, verbose_name="طول جغرافیایی", blank=True, null=True)
    lat = models.CharField(max_length=106, verbose_name="عرض جغرافیایی", blank=True, null=True)
    isp = models.CharField(max_length=107, verbose_name="ارائه‌دهنده اینترنت (ISP)", blank=True, null=True)
    viewd = models.BooleanField(default=False, verbose_name='تماشا شده')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='شروع حمله')
    trys = models.IntegerField(default=0, verbose_name='تعداد تلاش ها')

    def save(self, *args, **kwargs):
        if not self.id:  
            location_data = get_location_from_ip(self.ip_address)
            if location_data:
                self.country, self.region_name, self.city, self.zip_code, self.lat, self.lon, self.isp = location_data

        super().save(*args, **kwargs)

    def __str__(self):
        return f'تلاش نفوذ از {self.ip_address} در {self.city}, {self.country}'
    class Meta:
        verbose_name = "تلاش نفوذ"
        verbose_name_plural = "تلاش‌های نفوذ"

# class NotifModel(models.Model):
#     subject = models.CharField(max_length=100)
#     description = models.TextField()

#     def __str__(self):
#         return f'{self.subject[:30]}'

from product.models import ProductModel

class UserFavorites(models.Model):
    user = models.OneToOneField(User, verbose_name=_('User'), on_delete=models.CASCADE)
    products = models.ManyToManyField(ProductModel, verbose_name=_('Likes'), blank=True,)

    def __str__(self):
        return f'{self.user} likes'
    
    class Meta:
        verbose_name = _("User Favorites")
        verbose_name_plural = _("Users Favorites")