from rest_framework import serializers
from .models import Project
from django.db.models import Sum
from stamps.models import Stamp

def parse_duration_to_minutes(duration_str):
    """Parse duration string (HH:MM or decimal) to total minutes"""
    if not duration_str:
        return 0
    
    duration_str = str(duration_str).replace('hrs', '').strip()
    
    if ':' in duration_str:
        parts = duration_str.split(':')
        if len(parts) >= 2:
            try:
                hours = int(parts[0]) or 0
                minutes = int(parts[1]) or 0
                return (hours * 60) + minutes
            except (ValueError, IndexError):
                pass
    
    try:
        decimal_hours = float(duration_str)
        return int(decimal_hours * 60)
    except ValueError:
        return 0

def format_minutes_to_duration(total_minutes):
    """Format total minutes to HH:MM string"""
    if total_minutes == 0:
        return '00:00'
    hours = total_minutes // 60
    minutes = total_minutes % 60
    return f"{hours:02d}:{minutes:02d}"

class ProjectSerializer(serializers.ModelSerializer):
    # Map due_date to end_date if due_date is not provided but end_date is
    due_date = serializers.DateField(required=False, allow_null=True)
    total_hours_spent = serializers.SerializerMethodField()
    variance = serializers.SerializerMethodField()
    status_indicator = serializers.SerializerMethodField()
    last_activity_date = serializers.SerializerMethodField()
    active_users_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Project
        fields = [
            'id', 'name', 'code', 'estimated_time', 'sum_tasks_estimates',
            'due_date', 'client', 'is_public', 'created_at', 'updated_at',
            'total_hours_spent', 'variance', 'status_indicator', 
            'last_activity_date', 'active_users_count'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_total_hours_spent(self, obj):
        """Calculate total hours spent on project"""
        stamps = Stamp.objects.filter(project_id=obj.id)
        total_minutes = 0
        for stamp in stamps:
            if stamp.duration:
                total_minutes += parse_duration_to_minutes(stamp.duration)
        return format_minutes_to_duration(total_minutes)
    
    def get_variance(self, obj):
        """Calculate variance between estimated and actual hours"""
        stamps = Stamp.objects.filter(project_id=obj.id)
        total_minutes = 0
        for stamp in stamps:
            if stamp.duration:
                total_minutes += parse_duration_to_minutes(stamp.duration)
        
        estimated_minutes = parse_duration_to_minutes(obj.estimated_time) if obj.estimated_time else 0
        variance_minutes = total_minutes - estimated_minutes
        
        if estimated_minutes == 0:
            return {
                'formatted': format_minutes_to_duration(abs(variance_minutes)),
                'percentage': 0,
                'is_over': variance_minutes > 0
            }
        
        variance_percentage = (total_minutes / estimated_minutes * 100)
        return {
            'formatted': format_minutes_to_duration(abs(variance_minutes)),
            'percentage': round(variance_percentage, 1),
            'is_over': variance_minutes > 0
        }
    
    def get_status_indicator(self, obj):
        """Get project status indicator"""
        stamps = Stamp.objects.filter(project_id=obj.id)
        total_minutes = 0
        for stamp in stamps:
            if stamp.duration:
                total_minutes += parse_duration_to_minutes(stamp.duration)
        
        estimated_minutes = parse_duration_to_minutes(obj.estimated_time) if obj.estimated_time else 0
        
        if estimated_minutes == 0:
            return 'no_budget'
        
        variance_percentage = (total_minutes / estimated_minutes * 100) if estimated_minutes > 0 else 0
        
        if variance_percentage > 120:
            return 'over_budget'
        elif variance_percentage > 110:
            return 'at_risk'
        elif variance_percentage < 80:
            return 'under_budget'
        else:
            return 'on_track'
    
    def get_last_activity_date(self, obj):
        """Get last activity date"""
        last_stamp = Stamp.objects.filter(project_id=obj.id).order_by('-date', '-time').first()
        return last_stamp.date.isoformat() if last_stamp else None
    
    def get_active_users_count(self, obj):
        """Get count of active users (stamps in last 30 days)"""
        from django.utils import timezone
        from datetime import timedelta
        thirty_days_ago = timezone.now().date() - timedelta(days=30)
        active_user_ids = Stamp.objects.filter(
            project_id=obj.id,
            date__gte=thirty_days_ago
        ).values_list('user_id', flat=True).distinct()
        return len(set(active_user_ids))
    
    def to_representation(self, instance):
        """Map end_date to due_date if due_date is not set"""
        ret = super().to_representation(instance)
        if not ret.get('due_date') and instance.end_date:
            ret['due_date'] = instance.end_date
        return ret
    
    def to_internal_value(self, data):
        """Map due_date to end_date for saving"""
        if 'due_date' in data and data['due_date']:
            # Also set end_date if it's not already set
            if 'end_date' not in data:
                data['end_date'] = data['due_date']
        return super().to_internal_value(data)

