"""
Core models — maps every PHP database table faithfully.
All financial fields use DecimalField (never float).
"""
import random
import string
from decimal import Decimal
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin


def generate_mid():
    """Generate a Member ID in format OPT + 5 random digits (matching PHP PIN style)."""
    return 'OPT' + str(random.randint(10000, 99999))


class UserManager(BaseUserManager):
    def create_user(self, username, email, password=None, **extra_fields):
        if not username:
            raise ValueError('Username is required')
        if not email:
            raise ValueError('Email is required')
        email = self.normalize_email(email)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

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


class User(AbstractBaseUser, PermissionsMixin):
    """Maps to PHP `users` table. Also used for admin auth (is_admin_user flag)."""

    STATUS_CHOICES = [
        ('active', 'Active'),
        ('inactive', 'Inactive'),
        ('suspended', 'Suspended'),
    ]
    POSITION_CHOICES = [
        ('left', 'Left'),
        ('right', 'Right'),
    ]

    username = models.CharField(max_length=50, unique=True)
    email = models.EmailField(max_length=100, unique=True)
    full_name = models.CharField(max_length=100, blank=True, null=True)
    phone = models.CharField(max_length=20, blank=True, null=True)
    address = models.TextField(blank=True, null=True)
    post_office_number = models.CharField(max_length=20, blank=True, null=True)
    state = models.CharField(max_length=100, blank=True, null=True)
    country = models.CharField(max_length=100, blank=True, null=True)
    mid = models.CharField(max_length=20, unique=True, default=generate_mid)

    # MLM relationships
    sponsor = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='referrals')
    placement = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='placed_children')
    position = models.CharField(max_length=5, choices=POSITION_CHOICES, null=True, blank=True)
    default_placement = models.CharField(max_length=10, default='left')  # 'left', 'right', or 'auto'

    # MLM metrics — all Decimal (never float)
    rank_id = models.IntegerField(default=0)
    total_investment = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    left_leg_business = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    right_leg_business = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    rank_income_days = models.IntegerField(default=0)

    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='active')

    # Django auth fields
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_admin_user = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)

    objects = UserManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    class Meta:
        db_table = 'users'
        indexes = [
            models.Index(fields=['sponsor']),
            models.Index(fields=['placement']),
            models.Index(fields=['status']),
            models.Index(fields=['rank_id']),
            models.Index(fields=['mid']),
        ]

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


class Package(models.Model):
    """Maps to PHP `packages` table."""
    name = models.CharField(max_length=50)
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'packages'
        ordering = ['amount']

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


class Rank(models.Model):
    """Maps to PHP `ranks` table."""
    name = models.CharField(max_length=50)
    matching_business = models.DecimalField(max_digits=15, decimal_places=2)
    daily_income = models.DecimalField(max_digits=15, decimal_places=2)
    duration_days = models.IntegerField()
    total_cap_multiplier = models.DecimalField(max_digits=5, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'ranks'
        ordering = ['matching_business']

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


class Investment(models.Model):
    """Maps to PHP `investments` table."""
    STATUS_CHOICES = [
        ('active', 'Active'),
        ('completed', 'Completed'),
        ('capped', 'Capped'),
    ]

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='investments')
    package = models.ForeignKey(Package, on_delete=models.CASCADE)
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    roi_earned = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    total_earned = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    days_passed = models.IntegerField(default=0)
    last_roi_at = models.DateField(null=True, blank=True)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='active')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'investments'
        indexes = [
            models.Index(fields=['user']),
            models.Index(fields=['status']),
            models.Index(fields=['package']),
        ]

    def __str__(self):
        return f"Investment #{self.id} - {self.user.username} - ${self.amount}"


class Transaction(models.Model):
    """Maps to PHP `transactions` table — the complete financial ledger."""
    TYPE_CHOICES = [
        ('ROI', 'ROI'),
        ('LEVEL_INCOME', 'Level Income'),
        ('RANK_INCOME', 'Rank Income'),
        ('WITHDRAWAL', 'Withdrawal'),
        ('WITHDRAWAL_REFUND', 'Withdrawal Refund'),
        ('INVESTMENT', 'Investment'),
        ('DEPOSIT', 'Deposit'),
    ]
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('completed', 'Completed'),
        ('rejected', 'Rejected'),
    ]

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='transactions')
    related_user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='related_transactions')
    investment = models.ForeignKey(Investment, null=True, blank=True, on_delete=models.SET_NULL)
    level = models.IntegerField(null=True, blank=True)
    type = models.CharField(max_length=20, choices=TYPE_CHOICES)
    status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='completed')
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    fee = models.DecimalField(max_digits=15, decimal_places=2, default=Decimal('0.00'))
    net_amount = models.DecimalField(max_digits=15, decimal_places=2)
    description = models.TextField(blank=True, null=True)
    roi_date = models.DateField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'transactions'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user']),
            models.Index(fields=['type']),
            models.Index(fields=['status']),
            models.Index(fields=['created_at']),
            models.Index(fields=['investment']),
        ]

    def __str__(self):
        return f"{self.type} - {self.user.username} - ${self.amount}"


class Genealogy(models.Model):
    """Maps to PHP `genealogy` table — unilevel sponsor tree up to 12 levels."""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='genealogy_as_child')
    parent = models.ForeignKey(User, on_delete=models.CASCADE, related_name='genealogy_as_parent')
    level = models.IntegerField()

    class Meta:
        db_table = 'genealogy'
        indexes = [
            models.Index(fields=['user']),
            models.Index(fields=['parent']),
            models.Index(fields=['level']),
        ]

    def __str__(self):
        return f"L{self.level}: {self.user.username} -> {self.parent.username}"


class UserWallet(models.Model):
    """Maps to PHP `user_wallets` table."""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='wallets')
    network = models.CharField(max_length=50, default='TRC20')
    address = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'user_wallets'

    def __str__(self):
        return f"{self.user.username} - {self.network} - {self.address[:20]}..."


class Pin(models.Model):
    """Maps to PHP `pins` table."""
    STATUS_CHOICES = [
        ('unused', 'Unused'),
        ('used', 'Used'),
    ]

    pin_code = models.CharField(max_length=20, unique=True)
    package = models.ForeignKey(Package, on_delete=models.CASCADE)
    status = models.CharField(max_length=6, choices=STATUS_CHOICES, default='unused')
    assigned_to = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='assigned_pins')
    used_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='used_pins')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'pins'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['status']),
            models.Index(fields=['pin_code']),
        ]

    def __str__(self):
        return f"{self.pin_code} - {self.package.name} - {self.status}"


class MatchingSchedule(models.Model):
    """Maps to PHP `matching_schedules` table — binary slab matching 100-day contracts."""
    STATUS_CHOICES = [
        ('active', 'Active'),
        ('completed', 'Completed'),
    ]

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='matching_schedules')
    slab_amount = models.DecimalField(max_digits=15, decimal_places=2)
    daily_income = models.DecimalField(max_digits=15, decimal_places=2)
    days_passed = models.IntegerField(default=0)
    max_days = models.IntegerField(default=100)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='active')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'matching_schedules'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user']),
            models.Index(fields=['status']),
        ]

    def __str__(self):
        return f"Slab ${self.slab_amount} - {self.user.username} - {self.status}"


class MatchingMatch(models.Model):
    """Persistent ledger of consumed binary business per slab match.

    Each record represents one slab-worth of business consumed from
    the user's power and weaker legs.  The matching engine reads these
    records to determine how much business has already been consumed
    and must NOT be reused.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='matching_matches')
    slab_amount = models.DecimalField(max_digits=15, decimal_places=2)
    power_consumed = models.DecimalField(max_digits=15, decimal_places=2)
    weaker_consumed = models.DecimalField(max_digits=15, decimal_places=2)
    matched_amount = models.DecimalField(max_digits=15, decimal_places=2)
    matching_schedule = models.OneToOneField(
        MatchingSchedule, null=True, blank=True,
        on_delete=models.SET_NULL, related_name='matching_match'
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'matching_matches'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user']),
        ]

    def __str__(self):
        return f"Match ${self.slab_amount} - {self.user.username}"


class ConferredRank(models.Model):
    """Maps to PHP `conferred_ranks` table."""
    STATUS_CHOICES = [
        ('active', 'Active'),
        ('completed', 'Completed'),
    ]

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='conferred_ranks')
    downline = models.ForeignKey(User, on_delete=models.CASCADE, related_name='conferred_rank_from')
    rank = models.ForeignKey(Rank, on_delete=models.CASCADE)
    daily_income = models.DecimalField(max_digits=15, decimal_places=2)
    days_passed = models.IntegerField(default=0)
    max_days = models.IntegerField(default=100)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='active')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'conferred_ranks'

    def __str__(self):
        return f"Rank {self.rank.name} conferred to {self.user.username}"


class PasswordReset(models.Model):
    """Maps to PHP `password_resets` table."""
    email = models.EmailField(max_length=100)
    token = models.CharField(max_length=255)
    is_admin = models.BooleanField(default=False)
    expires_at = models.DateTimeField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'password_resets'


class CronLog(models.Model):
    """Maps to PHP `cron_logs` table — background job audit trail."""
    command = models.CharField(max_length=100)
    status = models.CharField(max_length=20, default='running')
    output = models.TextField(blank=True, null=True)
    error_message = models.TextField(blank=True, null=True)
    start_time = models.DateTimeField(auto_now_add=True)
    end_time = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = 'cron_logs'
        ordering = ['-start_time']

    def __str__(self):
        return f"{self.command} - {self.status} - {self.start_time}"
