import datetime

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone

from apps.account.managers.user_manager import (
    UserManager,
    UserCodeManager,
    UserVehicleManager,
    UserVehicleAssetManager,
    ContactUsManager,
    ContactUsAssetsManager,
    NewsLetterSubscriberManager,
)
from base.documents_path import DocumentsPath
from base.models import BaseModel


class User(AbstractUser, BaseModel):
    """
    This is the User model.
    It represents registered users in the system.

    Attributes:
        username (str): The username (maximum length 150 characters).
        email (str): The email address (unique, optional).
        mobile_number (str): The mobile number (maximum length 15 characters).
        mobile_country_code (str): The mobile country code (maximum length 5 characters).
        name (str): The user's name (optional, maximum length 30 characters).
        profile_pic (FileField): User's profile picture.

    Authentication:
        - The unique identifier for authentication is the 'mobile_number'.

    Methods:
        __str__(): Returns a string representation of the user.
    """

    username = models.CharField(max_length=150, null=False, blank=False)
    email = models.EmailField(blank=True, null=True, unique=True)
    mobile_number = models.CharField(max_length=15, null=True, blank=False, unique=True)
    mobile_country_code = models.CharField(max_length=5, null=True, blank=False)
    name = models.CharField(max_length=30, blank=True, null=True)
    profile_pic = models.FileField(
        upload_to=DocumentsPath.get_profile_picture_path, null=True
    )

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    objects = UserManager()

    def __str__(self):
        return f"{self.name}"

    class Meta:
        db_table = "users"


class UserCode(models.Model):
    """
    This is the UserCode model.

    It manages various types of user codes, such as login codes.

    Attributes:
        code (int): The numeric user code.
        user (ForeignKey): The associated user for whom the code is generated.
        timestamp (DateTimeField): The timestamp when the code was created.

    Meta Options:
        db_table (str): The database table name for this model.

    Methods:
        __str__(): Returns a string representation of the user code.
    """

    code = models.IntegerField(null=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_codes")
    timestamp = models.DateTimeField(
        default=timezone.now,
    )

    # Custom manager for UserCode
    objects = UserCodeManager()

    class Meta:
        db_table = "user_code"

    def __str__(self):
        """
        Returns a string representation of the user code.

        Returns:
            str: A string with the user's name and the associated code.
        """
        return f"Code for {self.user} is {self.code}"

    def is_expired(self):
        return self.timestamp < (timezone.now() - datetime.timedelta(seconds=120))


class UserNotification(BaseModel):
    """
    This is the UserNotification model.

    It represents notifications for users.

    Attributes:
        user (ForeignKey): The user to whom the notification is related.
        title (str): The title of the notification (non-null, non-blank).
        description (str): The description of the notification (non-null, non-blank).

    Meta Options:
        db_table (str): The database table name for this model.

    Methods:
        __str__(): Returns a string representation of the user notification.
    """

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="user_notifications"
    )
    title = models.CharField(null=False, blank=False)
    description = models.CharField(null=False, blank=False)

    class Meta:
        db_table = "user_notification"

    def __str__(self):
        """
        Returns a string representation of the user notification.

        Returns:
            str: A string with the user's name and the notification title.
        """
        return f"Notification for {self.user} is {self.title}"


class UserVehicle(BaseModel):
    """
    This is the UserVehicle model.

    It represents the vehicles owned by users.

    Attributes:
        vehicle_make (ForeignKey): The make of the vehicle.
        vehicle_model (ForeignKey): The model of the vehicle.
        connector (ForeignKey): The connector type associated with the vehicle.
        user (ForeignKey): The user who owns the vehicle.
        manufacturing_year (DateField): The manufacturing year of the vehicle (non-null, non-blank).
        vehicle_number (str): The vehicle's registration number (maximum length 30 characters, non-null, non-blank).

    Meta Options:
        db_table (str): The database table name for this model.

    Methods:
        __str__(): Returns a string representation of the user's vehicle.
    """

    vehicle_make = models.ForeignKey(
        "vehicle.VehicleMakeMaster",
        on_delete=models.CASCADE,
        related_name="vehicle_make_users",
    )
    vehicle_model = models.ForeignKey(
        "vehicle.VehicleModelMaster",
        on_delete=models.CASCADE,
        related_name="vehicle_model_users",
    )
    connector = models.ForeignKey(
        "master.ConnectorMaster",
        on_delete=models.CASCADE,
        related_name="connector_user_vehicles",
    )
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="user_vehicles",
    )
    manufacturing_year = models.IntegerField(
        null=False,
        blank=False,
    )
    vehicle_number = models.CharField(max_length=30, null=False, blank=False)

    objects = UserVehicleManager()

    class Meta:
        db_table = "user_vehicles"

    def __str__(self):
        """
        Returns a string representation of the user's vehicle.

        Returns:
            str: A string with the user's name and the vehicle model.
        """
        return f"Vehicle for {self.user} is {self.vehicle_model}"


class UserVehicleAssets(BaseModel):
    """
    Model class for representing user vehicle assets.

    This model represents assets related to a UserVehicle instance.

    Attributes:
        user_vehicle: ForeignKey to the UserVehicle model, establishing a relationship.
        asset: FileField for storing the asset file.
        objects: Custom manager for querying UserVehicleAsset instances.
    """

    user_vehicle = models.ForeignKey(
        UserVehicle,
        on_delete=models.CASCADE,
        related_name="user_vehicle_assets",
    )
    asset = models.FileField(upload_to=DocumentsPath.get_user_vehicle, null=True)

    objects = UserVehicleAssetManager()

    class Meta:
        """
        Meta class to specify database table name.
        """

        db_table = "user_vehicle_asset"

    def __str__(self):
        """
        String representation of the UserVehicleAssets instance.

        Returns:
            str: String representation.
        """
        return f"Asset for {self.user_vehicle}"


class ContactUs(BaseModel):
    """
    Model class for representing user contact information.

    This model represents user contact information for inquiries.

    Attributes:
        first_name (str): First name of the contact person.
        last_name (str): Last name of the contact person.
        email (str): Email address of the contact person.
        phone_number (str): Phone number of the contact person.
        subject (str): Subject of the contact inquiry.
        contact_request_type (str): Type of the contact request.
        description (str): Description of the contact inquiry.
        objects (UserVehicleAssetManager): Custom manager for querying UserVehicleAsset instances.
    """

    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    email = models.EmailField(max_length=100)
    phone_number = models.CharField(max_length=20)
    subject = models.CharField(max_length=250)
    contact_request_type = models.ForeignKey(
        "master.ContactUsRequestTypeMaster",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="request_type_contact_us",
    )
    description = models.TextField()

    objects = ContactUsManager()

    class Meta:
        """
        Meta class to specify database table name.
        """

        db_table = "contact_us"


class ContactUsAssets(BaseModel):
    """
    Model class for representing assets related to contact inquiries.

    This model represents assets related to a ContactUs instance.

    Attributes:
        contact_us (ContactUs): ForeignKey to the ContactUs model, establishing a relationship.
        asset (File): FileField for storing the asset file.
    """

    contact_us = models.ForeignKey(
        ContactUs,
        on_delete=models.CASCADE,
        related_name="contact_us_assets",
    )
    asset = models.FileField(upload_to=DocumentsPath.get_contact_us)

    objects = ContactUsAssetsManager()

    class Meta:
        """
        Meta class to specify database table name.
        """

        db_table = "assets_contact_us"


class NewsLetterSubscriber(BaseModel):
    """
    Model representing a newsletter subscriber.

    This model stores the email address of a newsletter subscriber.
    """

    email = models.EmailField(unique=True)

    objects = NewsLetterSubscriberManager()

    class Meta:
        """
        Meta class to specify database table name.
        """

        db_table = "newsletter_subscribers"
