from django.shortcuts import render, redirect
from django.contrib.auth.decorators import user_passes_test
from .forms import EmployeeForm, ContractForm, ChargeNumberForm, TimeLogForm, NewEmployeeForm
from .models import Contract, ChargeNumber, TimeCard, TimeCardCell, Employee
from django.utils import timezone
from django.db.models import Sum
from datetime import timedelta
import json

def is_admin(user):
    return user.is_active and user.is_superuser

@user_passes_test(is_admin)
def index(request):    
    contracts = Contract.objects.all()
    for c in contracts:
        total = TimeCardCell.objects.filter(charge_number__contract=c).aggregate(Sum('hour'))['hour__sum']
        c.total_logged = total if total else 0.0

    employees = Employee.objects.all()
    employee_data = []
    for e in employees:
        contract_hours = []
        for c in contracts:
            total_e_c = TimeCardCell.objects.filter(charge_number__contract=c, timeCard__employee=e).aggregate(Sum('hour'))['hour__sum']
            contract_hours.append({'contract': c, 'hours': total_e_c if total_e_c else 0.0})
        employee_data.append({'employee': e, 'contract_hours': contract_hours})

    return render(request, "financial/index.html", {
        'contracts': contracts,
        'employee_data': employee_data
    })

@user_passes_test(is_admin)
def new_employee(request):
    if request.method == "POST":
        form = NewEmployeeForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('financial_index')
    else:
        form = NewEmployeeForm()
    return render(request, 'financial/new_employee.html', {"form": form})

@user_passes_test(is_admin)
def contracts(request):
    contracts_list = Contract.objects.all()
    today = timezone.now().date()
    
    chart_data_list = []
    
    for c in contracts_list:
        cells = TimeCardCell.objects.filter(charge_number__contract=c).select_related('timeCard__employee').order_by('date')
        
        total_hours = sum((cell.hour or 0.0) for cell in cells)
        total_money = sum((cell.hour or 0.0) * cell.timeCard.employee.hourly_salary for cell in cells)
        
        c.total_hours_spent = total_hours
        c.total_money_spent = total_money
        c.remaining_hours = max(0, c.budget_hours - total_hours)
        
        budget_amt = c.funded_amount if c.funded_amount > 0 else c.proposed_amount
        c.remaining_money = max(0, budget_amt - total_money)
        
        proj_end = None
        
        if cells.exists():
            first_date = cells.first().date or c.baseline_start or today
            last_date = cells.last().date or today
            days_elapsed = (last_date - first_date).days
            if days_elapsed <= 0:
                days_elapsed = 1
                
            daily_hour_burn = total_hours / days_elapsed
            daily_money_burn = total_money / days_elapsed
            
            days_out_hours = (c.remaining_hours / daily_hour_burn) if daily_hour_burn > 0 else 9999
            days_out_money = (c.remaining_money / daily_money_burn) if daily_money_burn > 0 else 9999
            
            days_out = max(days_out_hours, days_out_money)
            
            if days_out < 9999:
                proj_end = last_date + timedelta(days=int(days_out))
        
        c.projected_end_date = proj_end if proj_end else "N/A"
        
        start_dt = str(c.baseline_start or today)
        end_dt = str(proj_end or (today + timedelta(days=30)))
        
        chart_data_list.append({
            'name': c.name,
            'start_date': start_dt,
            'today': str(today),
            'projected_end': end_dt,
            'budget': float(budget_amt),
            'spent': float(total_money),
            'remaining': float(c.remaining_money)
        })

    return render(request, 'financial/contracts.html', {
        'contracts': contracts_list,
        'chart_data_json': json.dumps(chart_data_list)
    })

@user_passes_test(is_admin)
def contract_detail(request, contract_slug):
    contract = Contract.objects.filter(slug=contract_slug).first()
    
    charge_numbers = contract.chargenumber_set.all() if contract else []
    mermaid_gantt_lines = []
    has_dates = False
    for cn in charge_numbers:
        if cn.start_date and cn.end_date:
            has_dates = True
            start = cn.start_date.strftime("%Y-%m-%d")
            end = cn.end_date.strftime("%Y-%m-%d")
            slug_label = cn.name or cn.slug or f"ID-{cn.id}"
            mermaid_gantt_lines.append(f"    {slug_label} : {start}, {end}")
            
    mermaid_gantt = None
    if has_dates:
        lines_str = "\n".join(mermaid_gantt_lines)
        mermaid_gantt = f"gantt\n    title {contract.name} Charge Numbers Timeline\n    dateFormat YYYY-MM-DD\n    section Charge Numbers\n{lines_str}"

    # --- EVM Data ---
    evm = contract.get_evm_data() if contract else {}
    evm_chart_json = json.dumps({
        'time_series': evm.get('time_series', []),
        'spi': evm.get('spi', 0),
        'cpi': evm.get('cpi', 0),
    })

    if request.method == 'POST':
        form = ContractForm(request.POST, instance=contract)
        if form.is_valid():
            form.save()
            return redirect('contracts')
    else:
        form = ContractForm(instance=contract)    
        charge_number_form = ChargeNumberForm()
        return render(request, 'financial/contract_detail.html', {
            'is_new': False, 
            'form': form, 
            'charge_number_form': charge_number_form, 
            'contract': contract,
            'charge_numbers': charge_numbers,
            'mermaid_gantt': mermaid_gantt,
            'evm': evm,
            'evm_chart_json': evm_chart_json,
        })

@user_passes_test(is_admin)
def new_contract(request):
    if request.method == "POST":
        form = ContractForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('contracts')
    else:
        form = ContractForm()
    return render(request, 'financial/contract_detail.html', {"form": form, 'is_new': True})

@user_passes_test(is_admin)
def timekeeping(request):
    if request.method == "POST":
        form = TimeLogForm(request.POST)
        if form.is_valid():
            employee, _ = Employee.objects.get_or_create(user=request.user)
            
            time_card, _ = TimeCard.objects.get_or_create(employee=employee, startDate=timezone.now().date(), endDate=timezone.now().date())
            cell = form.save(commit=False)
            cell.timeCard = time_card
            cell.save()
            return redirect('financial_index')
    else:
        form = TimeLogForm()
    return render(request, 'financial/timekeeping.html', {'form': form})

@user_passes_test(is_admin)
def time_logs(request):
    logs = TimeCardCell.objects.select_related(
        'timeCard__employee__user',
        'charge_number__contract',
    ).order_by('-date', '-created')

    employee_ids = []
    for raw in request.GET.getlist('employee'):
        if raw:
            try:
                employee_ids.append(int(raw))
            except (ValueError, TypeError):
                pass
    month = request.GET.get('month')
    contract_id = request.GET.get('contract')
    charge_number_id = request.GET.get('charge_number')

    if employee_ids:
        logs = logs.filter(timeCard__employee_id__in=employee_ids)
    if month:
        try:
            year, mon = month.split('-', 1)
            logs = logs.filter(date__year=int(year), date__month=int(mon))
        except (ValueError, TypeError):
            pass
    if contract_id:
        logs = logs.filter(charge_number__contract_id=contract_id)
    if charge_number_id:
        logs = logs.filter(charge_number_id=charge_number_id)

    charge_numbers = ChargeNumber.objects.select_related('contract').order_by('contract__name', 'name')
    if contract_id:
        charge_numbers = charge_numbers.filter(contract_id=contract_id)

    contract_totals = (
        logs.filter(charge_number__isnull=False)
        .values('charge_number__contract_id', 'charge_number__contract__name')
        .annotate(total_hours=Sum('hour'))
        .order_by('charge_number__contract__name')
    )
    charge_number_totals = (
        logs.filter(charge_number__isnull=False)
        .values(
            'charge_number_id',
            'charge_number__name',
            'charge_number__contract__name',
        )
        .annotate(total_hours=Sum('hour'))
        .order_by('charge_number__contract__name', 'charge_number__name')
    )
    grand_total = logs.aggregate(total_hours=Sum('hour'))['total_hours'] or 0.0

    return render(request, 'financial/time_logs.html', {
        'logs': logs,
        'employees': Employee.objects.select_related('user').order_by('user__last_name', 'user__first_name'),
        'contracts': Contract.objects.order_by('name'),
        'charge_numbers': charge_numbers,
        'contract_totals': contract_totals,
        'charge_number_totals': charge_number_totals,
        'grand_total': grand_total,
        'filters': {
            'employees': [str(eid) for eid in employee_ids],
            'month': month or '',
            'contract': contract_id or '',
            'charge_number': charge_number_id or '',
        },
    })

@user_passes_test(is_admin)
def edit_time_log(request, log_id):
    log_entry = TimeCardCell.objects.filter(id=log_id).first()
    if not log_entry:
        return redirect('time_logs')
        
    if request.method == "POST":
        form = TimeLogForm(request.POST, instance=log_entry)
        if form.is_valid():
            form.save()
            return redirect('time_logs')
    else:
        form = TimeLogForm(instance=log_entry)
        
    return render(request, 'financial/edit_time_log.html', {'form': form, 'log': log_entry})

@user_passes_test(is_admin)
def delete_time_log(request, log_id):
    if request.method == "POST":
        log_entry = TimeCardCell.objects.filter(id=log_id).first()
        if log_entry:
            log_entry.delete()
    return redirect('time_logs')

@user_passes_test(is_admin)
def client_reports(request):
    contracts = Contract.objects.all()
    for c in contracts:
        total = TimeCardCell.objects.filter(charge_number__contract=c).aggregate(Sum('hour'))['hour__sum']
        c.total_logged = total if total else 0.0
        c.remaining_budget = c.budget_hours - c.total_logged
    return render(request, 'financial/reports.html', {'contracts': contracts})

@user_passes_test(is_admin)
def update_charge_number(request, charge_number_slug):
    charge_number = ChargeNumber.objects.filter(slug=charge_number_slug).first()
    if not charge_number:
        return redirect('contracts')
    
    if request.method == "POST":
        form = ChargeNumberForm(request.POST, instance=charge_number)
        if form.is_valid():
            form.save()
            return redirect('contract_detail', contract_slug=charge_number.contract.slug)
    else:
        form = ChargeNumberForm(instance=charge_number)
        
    return render(request, 'financial/update_charge_number.html', {
        'form': form,
        'charge_number': charge_number,
    })

@user_passes_test(is_admin)
def new_charge_number(request, contract_slug):
    contract = Contract.objects.filter(slug=contract_slug).first()
    if request.method == "POST":
        form = ChargeNumberForm(request.POST)
        if form.is_valid():
            charge_number = form.save(commit=False)
            charge_number.contract = contract
            charge_number.save()
            return redirect('contract_detail', contract_slug=contract.slug)
    return redirect('contract_detail', contract_slug=contract_slug)

@user_passes_test(is_admin)
def timeapproval(request):
    return render(request, 'financial/not_created.html', {})

@user_passes_test(is_admin)
def chargenumber(request):
    return render(request, 'financial/not_created.html', {})

@user_passes_test(is_admin)
def procurement(request):
    return render(request, 'financial/procurement.html', {})

@user_passes_test(is_admin)
def profile(request):
    form = EmployeeForm()
    return render(request, 'financial/profile.html', {'form': form})