"""
Binary Tree models for the Hybrid Global Assisted Binary compensation system.

Models:
  BinaryTreeMetrics        — cached per-distributor binary tree stats
  BinaryPlacementLog       — audit trail for every binary placement decision
  BinaryLevelSnapshot      — per-distributor level progress based on binary subtree
  PowerStreamForfeitureLog — audit log when a power stream bonus is forfeited to company
"""

import uuid

from django.conf import settings
from django.db import models

from apps.core.models import BaseModel


class BinaryTreeMetrics(models.Model):
    """
    Cached binary tree metrics per DistributorID.
    Rebuilt by the rebuild_binary_metrics Celery task.
    Read by the dashboard and binary-analysis API to avoid real-time traversal.
    """

    distributor = models.OneToOneField(
        'distributor.DistributorID',
        on_delete=models.CASCADE,
        related_name='binary_metrics',
        primary_key=True,
    )
    left_volume = models.PositiveIntegerField(default=0, help_text='Total nodes in LEFT subtree')
    right_volume = models.PositiveIntegerField(default=0, help_text='Total nodes in RIGHT subtree')
    subtree_total = models.PositiveIntegerField(default=0, help_text='left_volume + right_volume')
    direct_left_count = models.PositiveIntegerField(default=0, help_text='Direct LEFT children count (0 or 1)')
    direct_right_count = models.PositiveIntegerField(default=0, help_text='Direct RIGHT children count (0 or 1)')
    tree_depth = models.PositiveIntegerField(default=0, help_text='Depth of this subtree')
    weak_leg = models.CharField(
        max_length=8, blank=True, default='',
        choices=[('LEFT', 'Left'), ('RIGHT', 'Right'), ('BALANCED', 'Balanced')],
        help_text='Side with fewer nodes',
    )
    strong_leg = models.CharField(
        max_length=8, blank=True, default='',
        choices=[('LEFT', 'Left'), ('RIGHT', 'Right'), ('BALANCED', 'Balanced')],
        help_text='Side with more nodes',
    )
    imbalance_ratio = models.DecimalField(
        max_digits=5, decimal_places=2, default=0,
        help_text='0 = perfect balance; 100 = completely one-sided',
    )
    last_rebuilt_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Binary Tree Metrics'
        verbose_name_plural = 'Binary Tree Metrics'
        indexes = [
            models.Index(fields=['subtree_total']),
            models.Index(fields=['weak_leg']),
            models.Index(fields=['last_rebuilt_at']),
        ]

    def __str__(self):
        return (
            f"BTMetrics({self.distributor_id}) "
            f"L={self.left_volume} R={self.right_volume} "
            f"total={self.subtree_total}"
        )


class BinaryPlacementLog(BaseModel):
    """
    Audit trail for every binary tree placement decision.
    Placement type:
      DIRECT   — first or second direct referral of sponsor (goes LEFT or RIGHT)
      SPILLOVER — BFS spillover; sponsor's subtree was full on that leg
    """

    class PlacementType(models.TextChoices):
        DIRECT = 'DIRECT', 'Direct'
        SPILLOVER = 'SPILLOVER', 'Spillover'

    class BinaryPosition(models.TextChoices):
        LEFT = 'LEFT', 'Left'
        RIGHT = 'RIGHT', 'Right'

    distributor = models.ForeignKey(
        'distributor.DistributorID',
        on_delete=models.CASCADE,
        related_name='placement_logs',
        db_index=True,
    )
    binary_parent = models.ForeignKey(
        'distributor.DistributorID',
        on_delete=models.CASCADE,
        related_name='placement_parent_logs',
        db_index=True,
    )
    binary_position = models.CharField(max_length=5, choices=BinaryPosition.choices, db_index=True)
    placement_type = models.CharField(max_length=10, choices=PlacementType.choices, db_index=True)
    sponsor = models.ForeignKey(
        'distributor.DistributorID',
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='sponsored_placements',
    )
    notes = models.TextField(blank=True, default='')

    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['distributor']),
            models.Index(fields=['binary_parent', 'binary_position']),
            models.Index(fields=['created_at']),
        ]

    def __str__(self):
        return (
            f"Placement: {self.distributor_id} → "
            f"{self.binary_position} of {self.binary_parent_id} "
            f"({self.placement_type})"
        )


class BinaryLevelSnapshot(BaseModel):
    """
    Snapshot of binary-based level progress per DistributorID.
    Separate from DistributorLevelProgress (which is global-position based)
    so both can be queried for migration analytics.
    Over time, DistributorLevelProgress will be redirected to use binary counts.
    """

    distributor = models.OneToOneField(
        'distributor.DistributorID',
        on_delete=models.CASCADE,
        related_name='binary_level_snapshot',
    )
    subtree_total = models.PositiveIntegerField(default=0)
    left_volume = models.PositiveIntegerField(default=0)
    right_volume = models.PositiveIntegerField(default=0)
    current_level = models.PositiveIntegerField(default=0)
    last_completed_level = models.PositiveIntegerField(default=0)
    next_level = models.PositiveIntegerField(null=True, blank=True)
    next_level_required = models.PositiveIntegerField(null=True, blank=True)
    positions_to_next = models.PositiveIntegerField(default=0)
    progress_percent = models.DecimalField(max_digits=5, decimal_places=1, default=0)
    calculated_at = models.DateTimeField(auto_now=True)

    class Meta:
        indexes = [
            models.Index(fields=['current_level']),
            models.Index(fields=['calculated_at']),
        ]

    def __str__(self):
        return f"BLevelSnapshot({self.distributor_id}) level={self.current_level}"


class PowerStreamForfeitureLog(BaseModel):
    """
    Audit record created whenever a power stream bonus is forfeited to the company.
    Triggered by the expire_overdue_power_stream_bonuses Celery task.
    """

    bonus_record = models.OneToOneField(
        'power_stream.PowerStreamBonusRecord',
        on_delete=models.CASCADE,
        related_name='forfeiture_log',
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='forfeiture_logs',
        db_index=True,
    )
    gross_amount = models.DecimalField(max_digits=12, decimal_places=2)
    net_amount = models.DecimalField(max_digits=12, decimal_places=2)
    forfeited_at = models.DateTimeField(auto_now_add=True, db_index=True)
    reason = models.TextField(blank=True, default='')
    grace_expired = models.BooleanField(default=False, help_text='True if expired after grace period')

    class Meta:
        ordering = ['-forfeited_at']
        indexes = [
            models.Index(fields=['user', 'forfeited_at']),
            models.Index(fields=['forfeited_at']),
        ]

    def __str__(self):
        return f"Forfeiture: user={self.user_id} net={self.net_amount} at={self.forfeited_at}"
