from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from django.utils import timezone


class Permission(models.Model):
    key = models.CharField(max_length=80, unique=True, db_index=True)
    name = models.CharField(max_length=120)
    category = models.CharField(max_length=40)

    class Meta:
        db_table = "permissions"


class Role(models.Model):
    name = models.CharField(max_length=60)
    slug = models.CharField(max_length=20, null=True, blank=True, unique=True, db_index=True)
    is_system = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)
    permissions = models.ManyToManyField(Permission, through="RolePermission", related_name="roles")

    class Meta:
        db_table = "roles"


class UserManager(BaseUserManager):
    def create_user(self, username, password=None, **extra_fields):
        if not username:
            raise ValueError("username is required")
        user = self.model(username=username, **extra_fields)
        if password:
            user.set_password(password)
        else:
            user.set_unusable_password()
        user.save(using=self._db)
        return user

    def create_superuser(self, username, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        return self.create_user(username, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=80, unique=True, db_index=True)
    password = models.CharField(max_length=255, db_column="password_hash")
    role = models.CharField(max_length=20, default="user")
    role_obj = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True, blank=True, db_column="role_id")
    created_at = models.DateTimeField(default=timezone.now)
    invite_token = models.CharField(max_length=64, null=True, blank=True, unique=True, db_index=True)
    invite_expires_at = models.DateTimeField(null=True, blank=True)
    reset_token = models.CharField(max_length=64, null=True, blank=True, unique=True, db_index=True)
    reset_expires_at = models.DateTimeField(null=True, blank=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    direct_permissions = models.ManyToManyField(Permission, through="UserPermission", related_name="user_set")

    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = []

    objects = UserManager()

    class Meta:
        db_table = "users"


class UserPermission(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, db_column="user_id")
    permission = models.ForeignKey(Permission, on_delete=models.CASCADE, db_column="permission_id")

    class Meta:
        db_table = "user_permissions"
        unique_together = (("user", "permission"),)


class RolePermission(models.Model):
    role = models.ForeignKey(Role, on_delete=models.CASCADE, db_column="role_id")
    permission = models.ForeignKey(Permission, on_delete=models.CASCADE, db_column="permission_id")

    class Meta:
        db_table = "role_permissions"
        unique_together = (("role", "permission"),)


class DashboardSession(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    token = models.CharField(max_length=64, unique=True, db_index=True)
    expires_at = models.DateTimeField()
    remember_me = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)
    otp_verified_at = models.DateTimeField(null=True, blank=True)
    otp_code_hash = models.CharField(max_length=255, null=True, blank=True)
    otp_expires_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = "sessions"
