from django.core.management.base import BaseCommand
from stamps.models import Stamp
from functions.models import Function
from worktimeservice.service import calculate_daily_balances_for_user_and_date
from worktimeservice.models import WorkBalance
from balancedetail.models import BalanceDetail
from datetime import date
import uuid


def normalize_user_id(user_id):
    """
    Normalize user_id to standard UUID format with dashes.
    Converts 'edd631c63c1848c681244f5c7c868801' to 'edd631c6-3c18-48c6-8124-4f5c7c868801'
    """
    if not user_id:
        return user_id
    
    # Remove any existing dashes
    user_id_clean = str(user_id).replace('-', '')
    
    # If it's a valid 32-character hex string, format it as UUID
    if len(user_id_clean) == 32:
        try:
            # Parse as UUID and return in standard format
            uuid_obj = uuid.UUID(user_id_clean)
            return str(uuid_obj)
        except (ValueError, AttributeError):
            # If it's not a valid UUID, return as-is
            return user_id
    
    # If it's already in UUID format, return as-is
    try:
        uuid_obj = uuid.UUID(str(user_id))
        return str(uuid_obj)
    except (ValueError, AttributeError):
        # If it's not a valid UUID format, return as-is
        return user_id


class Command(BaseCommand):
    help = 'Debug balance calculation for a specific user and date'

    def add_arguments(self, parser):
        parser.add_argument(
            '--user-id',
            type=str,
            required=True,
            help='User ID to debug',
        )
        parser.add_argument(
            '--date',
            type=str,
            required=True,
            help='Date to debug (YYYY-MM-DD format)',
        )

    def handle(self, *args, **options):
        user_id_raw = options['user_id']
        date_str = options['date']
        
        # Normalize user_id to ensure it's in the correct UUID format with dashes
        user_id = normalize_user_id(user_id_raw)
        
        if user_id != user_id_raw:
            self.stdout.write(self.style.WARNING(f"User ID normalized: '{user_id_raw}' -> '{user_id}'"))
        
        # Parse date
        try:
            year, month, day = map(int, date_str.split('-'))
            check_date = date(year, month, day)
        except Exception as e:
            self.stdout.write(self.style.ERROR(f'Invalid date format: {date_str}. Use YYYY-MM-DD'))
            return
        
        self.stdout.write("=" * 80)
        self.stdout.write(f"DEBUGGING BALANCE CALCULATION")
        self.stdout.write(f"User ID: {user_id}")
        self.stdout.write(f"Date: {check_date}")
        self.stdout.write("=" * 80)
        self.stdout.write("")
        
        # 1. Check stamps for this date
        self.stdout.write("1. CHECKING STAMPS")
        self.stdout.write("-" * 80)
        stamps = Stamp.objects.filter(user_id=user_id, date=check_date).order_by('time')
        if stamps.exists():
            self.stdout.write(self.style.SUCCESS(f"Found {stamps.count()} stamp(s):"))
            for stamp in stamps:
                self.stdout.write(f"  - {stamp.stamp_function} at {stamp.time}")
        else:
            self.stdout.write(self.style.ERROR("No stamps found for this date"))
            return
        self.stdout.write("")
        
        # 2. Check Function objects
        self.stdout.write("2. CHECKING FUNCTION OBJECTS")
        self.stdout.write("-" * 80)
        function_map = {f.function_ref_id: f for f in Function.objects.all()}
        self.stdout.write(f"Total functions in database: {len(function_map)}")
        
        for stamp in stamps:
            func_obj = function_map.get(stamp.stamp_function)
            if func_obj:
                self.stdout.write(f"  ✓ {stamp.stamp_function}:")
                self.stdout.write(f"    - name: {func_obj.name}")
                self.stdout.write(f"    - out: {func_obj.out}")
                self.stdout.write(f"    - break_flag: {func_obj.break_flag}")
                self.stdout.write(f"    - with_reason: {getattr(func_obj, 'with_reason', False)}")
            else:
                self.stdout.write(self.style.ERROR(f"  ✗ {stamp.stamp_function}: Function NOT FOUND in database"))
        self.stdout.write("")
        
        # 3. Check current WorkBalance
        self.stdout.write("3. CHECKING CURRENT WORKBALANCE")
        self.stdout.write("-" * 80)
        balance = WorkBalance.objects.filter(user_id=user_id, date=check_date).first()
        if balance:
            self.stdout.write(f"Current balance:")
            self.stdout.write(f"  - total_work_seconds: {balance.total_work_seconds} ({balance.total_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - regular_work_seconds: {balance.regular_work_seconds} ({balance.regular_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - net_work_seconds: {balance.net_work_seconds} ({balance.net_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - total_work_seconds: {balance.total_work_seconds} ({balance.total_work_seconds / 3600:.2f} hours)")
        else:
            self.stdout.write(self.style.WARNING("No WorkBalance record found"))
        self.stdout.write("")
        
        # 4. Recalculate and show what happens
        self.stdout.write("4. RECALCULATING BALANCE")
        self.stdout.write("-" * 80)
        try:
            # Force recalculation - this should save to database
            result = calculate_daily_balances_for_user_and_date(user_id, check_date)
            if result:
                self.stdout.write(self.style.SUCCESS("Calculation completed"))
                self.stdout.write(f"  - Returned WorkBalance ID: {result.id}")
                self.stdout.write(f"  - Returned total_work_seconds: {result.total_work_seconds} ({result.total_work_seconds / 3600:.2f} hours)")
                self.stdout.write(f"  - Returned regular_work_seconds: {result.regular_work_seconds} ({result.regular_work_seconds / 3600:.2f} hours)")
                self.stdout.write(f"  - Returned net_work_seconds: {result.net_work_seconds} ({result.net_work_seconds / 3600:.2f} hours)")
                
                # Force save to ensure it's persisted
                result.save()
                result.refresh_from_db()
                self.stdout.write(f"  - After explicit save: total_work_seconds={result.total_work_seconds}")
            else:
                self.stdout.write(self.style.WARNING("Calculation returned None (no stamps or deleted balance)"))
        except Exception as e:
            self.stdout.write(self.style.ERROR(f"Calculation failed: {e}"))
            import traceback
            self.stdout.write(traceback.format_exc())
        self.stdout.write("")
        
        # 5. Check WorkBalance after recalculation
        self.stdout.write("5. CHECKING WORKBALANCE AFTER RECALCULATION")
        self.stdout.write("-" * 80)
        # Force a fresh query from the database (no cache)
        from django.db import connection
        connection.queries_log.clear()  # Clear query cache
        balance_after = WorkBalance.objects.filter(user_id=user_id, date=check_date).first()
        if balance_after:
            # Refresh from database to ensure we have the latest values
            balance_after.refresh_from_db()
            self.stdout.write(f"Balance after recalculation:")
            self.stdout.write(f"  - ID: {balance_after.id}")
            self.stdout.write(f"  - total_work_seconds: {balance_after.total_work_seconds} ({balance_after.total_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - regular_work_seconds: {balance_after.regular_work_seconds} ({balance_after.regular_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - daily_break_seconds: {balance_after.daily_break_seconds} ({balance_after.daily_break_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - net_work_seconds: {balance_after.net_work_seconds} ({balance_after.net_work_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - overtime_seconds: {balance_after.overtime_seconds} ({balance_after.overtime_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - flex_seconds: {balance_after.flex_seconds} ({balance_after.flex_seconds / 3600:.2f} hours)")
            self.stdout.write(f"  - created_at: {balance_after.created_at}")
            self.stdout.write(f"  - updated_at: {balance_after.updated_at}")
            
            if balance_after.total_work_seconds == 0:
                self.stdout.write("")
                self.stdout.write(self.style.ERROR("⚠️  WARNING: total_work_seconds is still 0 after recalculation!"))
                self.stdout.write("This suggests the calculation logic isn't finding work intervals.")
        else:
            self.stdout.write(self.style.WARNING("No WorkBalance record found after recalculation"))
        self.stdout.write("")
        
        # 6. Check BalanceDetail records
        self.stdout.write("6. CHECKING BALANCEDETAIL RECORDS")
        self.stdout.write("-" * 80)
        balance_details = BalanceDetail.objects.filter(
            user_id=user_id,
            date=check_date
        ).select_related('paycode')
        
        if balance_details.exists():
            self.stdout.write(self.style.SUCCESS(f"Found {balance_details.count()} BalanceDetail record(s):"))
            for detail in balance_details:
                paycode_name = detail.paycode.name if detail.paycode else "No Paycode"
                self.stdout.write(f"  - Paycode: {paycode_name}")
                self.stdout.write(f"    - total_work_seconds: {detail.total_work_seconds} ({detail.total_work_seconds / 3600:.2f} hours)")
                self.stdout.write(f"    - regular_work_seconds: {detail.regular_work_seconds} ({detail.regular_work_seconds / 3600:.2f} hours)")
                self.stdout.write(f"    - net_work_seconds: {detail.net_work_seconds} ({detail.net_work_seconds / 3600:.2f} hours)")
                self.stdout.write(f"    - overtime_seconds: {detail.overtime_seconds} ({detail.overtime_seconds / 3600:.2f} hours)")
        else:
            self.stdout.write(self.style.WARNING("No BalanceDetail records found for this date"))
        self.stdout.write("")
        
        # 7. Verify database persistence
        self.stdout.write("7. VERIFYING DATABASE PERSISTENCE")
        self.stdout.write("-" * 80)
        
        # Check WorkBalance via raw SQL
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT id, total_work_seconds, regular_work_seconds, net_work_seconds, updated_at "
                "FROM workbalances WHERE user_id = %s AND date = %s",
                [user_id, check_date]
            )
            row = cursor.fetchone()
            if row:
                self.stdout.write(self.style.SUCCESS("✓ WorkBalance found in database via raw SQL:"))
                self.stdout.write(f"  - ID: {row[0]}")
                self.stdout.write(f"  - total_work_seconds: {row[1]} ({row[1] / 3600:.2f} hours)")
                self.stdout.write(f"  - regular_work_seconds: {row[2]} ({row[2] / 3600:.2f} hours)")
                self.stdout.write(f"  - net_work_seconds: {row[3]} ({row[3] / 3600:.2f} hours)")
                self.stdout.write(f"  - updated_at: {row[4]}")
                
                if row[1] == 0:
                    self.stdout.write("")
                    self.stdout.write(self.style.ERROR("⚠️  WARNING: Database shows total_work_seconds=0 even after calculation!"))
            else:
                self.stdout.write(self.style.ERROR("✗ WorkBalance NOT found in database via raw SQL"))
        
        # Check BalanceDetail via raw SQL
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT COUNT(*) FROM balancedetail_balancedetail WHERE user_id = %s AND date = %s",
                [user_id, check_date]
            )
            count = cursor.fetchone()[0]
            if count > 0:
                self.stdout.write(self.style.SUCCESS(f"✓ Found {count} BalanceDetail record(s) in database"))
            else:
                self.stdout.write(self.style.WARNING("⚠ No BalanceDetail records found in database"))
        self.stdout.write("")
        
        # 8. Summary
        self.stdout.write("=" * 80)
        self.stdout.write("SUMMARY")
        self.stdout.write("=" * 80)
        
        issues = []
        if not stamps.exists():
            issues.append("No stamps found for this date")
        else:
            missing_functions = [s.stamp_function for s in stamps if function_map.get(s.stamp_function) is None]
            if missing_functions:
                issues.append(f"Missing Function objects: {missing_functions}")
            
            if balance_after and balance_after.total_work_seconds == 0:
                issues.append("Balance is 0.0 even though stamps exist - calculation logic issue")
        
        if issues:
            self.stdout.write(self.style.ERROR("ISSUES FOUND:"))
            for issue in issues:
                self.stdout.write(f"  - {issue}")
        else:
            self.stdout.write(self.style.SUCCESS("No obvious issues found"))
        
        self.stdout.write("")
        self.stdout.write("=" * 80)

