from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse, Http404
from django.views.decorators.http import require_POST
from django.db.models import Count, Q
from django.utils import timezone
from datetime import datetime, timedelta
from accounts.models import User
from scheduler.models import AppointmentType, AvailabilityRule, BlockedPeriod, ExceptionDay, Business, Resource
from .models import Appointment
import json
import csv
from django.http import HttpResponse

@login_required
def appointments_view(request):
    resources = Resource.objects.filter(user=request.user, deleted_at__isnull=True)
    appt_types = AppointmentType.objects.filter(user=request.user, deleted_at__isnull=True)
    return render(request, 'booking/appointments_list.html', {
        'resources': resources,
        'appt_types': appt_types,
        'statuses': Appointment.STATUS_CHOICES
    })

@login_required
def appointments_api(request):
    date_from = request.GET.get('date_from')
    date_to = request.GET.get('date_to')
    resource_id = request.GET.get('resource_id')
    appt_type_id = request.GET.get('service_id')
    status = request.GET.get('status')
    search = request.GET.get('search')

    qs = Appointment.objects.filter(user=request.user).select_related(
        'appointment_type',
        'resource'
    ).order_by('-date', '-start_time')

    if date_from:
        qs = qs.filter(date__gte=date_from)
    if date_to:
        qs = qs.filter(date__lte=date_to)
    if resource_id:
        qs = qs.filter(resource_id=resource_id)
    if appt_type_id:
        qs = qs.filter(appointment_type_id=appt_type_id)
    if status:
        qs = qs.filter(status=status)
    if search:
        qs = qs.filter(
            Q(full_name__icontains=search) |
            Q(email__icontains=search) |
            Q(phone__icontains=search)
        )

    data = []
    for appt in qs:
        data.append({
            'id': appt.id,
            'date': appt.date.strftime('%Y-%m-%d'),
            'time': appt.start_time.strftime('%H:%M'),
            'client': appt.full_name,
            'email': appt.email,
            'phone': appt.phone,
            'service': appt.appointment_type.name,
            'professional': appt.resource.name if appt.resource else 'General',
            'status': appt.status,
            'status_display': appt.get_status_display()
        })

    return JsonResponse({'success': True, 'data': data})

@require_POST
@login_required
def appointment_status_update(request, pk):
    appointment = get_object_or_404(Appointment, pk=pk, user=request.user)
    new_status = request.POST.get('status')
    if new_status in dict(Appointment.STATUS_CHOICES):
        appointment.status = new_status
        appointment.save()
        return JsonResponse({'success': True, 'message': 'Estado actualizado'})
    return JsonResponse({'success': False, 'error': 'Estado inválido'}, status=400)

@login_required
def appointments_export(request):
    qs = Appointment.objects.filter(user=request.user).order_by('-date', '-start_time')
    
    # Podríamos aplicar los mismos filtros aquí si quisiéramos exportar el filtrado
    
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="citalis_citas.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Fecha', 'Hora', 'Cliente', 'Email', 'Teléfono', 'Servicio', 'Profesional', 'Estado'])
    
    for appt in qs:
        writer.writerow([
            appt.date, 
            appt.start_time, 
            appt.full_name, 
            appt.email, 
            appt.phone, 
            appt.appointment_type.name, 
            appt.resource.name if appt.resource else 'General',
            appt.get_status_display()
        ])
        
    return response

def business_landing(request):
    business = Business.get_current()
    if business is None:
        raise Http404("No hay un negocio configurado.")
    # Obtener servicios activos y no eliminados
    services = AppointmentType.objects.filter(
        user=business.user,
        is_active=True,
        deleted_at__isnull=True
    ).order_by('name')

    return render(request, 'booking/business_landing.html', {
        'business': business,
        'services': services
    })

def public_booking_page(request, slug):
    business = Business.get_current()
    if business is None:
        raise Http404("No hay un negocio configurado.")
    owner = business.user
    # Filtrar solo servicios NO eliminados y activos
    appt_type = get_object_or_404(AppointmentType, user=owner, slug=slug, is_active=True, deleted_at__isnull=True)
    
    if request.method == 'POST':
        date_str = request.POST.get('date')
        time_str = request.POST.get('time')
        date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
        start_time_obj = datetime.strptime(time_str, '%H:%M').time()
        end_time_obj = (datetime.combine(date_obj, start_time_obj) + timedelta(minutes=appt_type.duration_minutes)).time()
        
        # Validar disponibilidad y encontrar recurso
        available_resource = find_available_resource(appt_type, date_obj, start_time_obj, end_time_obj)
        
        if not available_resource:
            return render(request, 'booking/public_booking.html', {
                'owner': owner,
                'business': business,
                'appt_type': appt_type,
                'error': 'Ese horario ya no está disponible.'
            })
            
        appointment = Appointment.objects.create(
            user=owner,
            resource=available_resource,
            appointment_type=appt_type,
            date=date_obj,
            start_time=start_time_obj,
            end_time=end_time_obj,
            full_name=request.POST.get('full_name'),
            email=request.POST.get('email'),
            phone=request.POST.get('phone'),
            document_type=request.POST.get('document_type'),
            document_number=request.POST.get('document_number'),
            status='confirmed'
        )
        return render(request, 'booking/success.html', {
            'appointment': appointment,
            'business': business,
            'appt_type': appt_type
        })

    return render(request, 'booking/public_booking.html', {
        'owner': owner,
        'business': business,
        'appt_type': appt_type,
        'today': timezone.now().date()
    })

def available_times_api(request):
    slug = request.GET.get('slug')
    date_str = request.GET.get('date')

    if not all([slug, date_str]):
        return JsonResponse({'error': 'Parámetros insuficientes'}, status=400)

    try:
        date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
        business = Business.get_current()
        if business is None:
            return JsonResponse({'error': 'No hay un negocio configurado.'}, status=404)
        appt_type = get_object_or_404(AppointmentType, user=business.user, slug=slug, deleted_at__isnull=True)
        
        times, is_exception, is_blocked, reason = get_available_times_logic(business.user, appt_type, date_obj)
        
        return JsonResponse({
            'available_times': times,
            'is_exception': is_exception,
            'is_blocked': is_blocked,
            'reason': reason
        })
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

def get_available_times_logic(owner, appt_type, date_obj):
    # 1. ExceptionDay
    exception = ExceptionDay.objects.filter(user=owner, date=date_obj).first()
    if exception:
        if not exception.is_available:
            return [], False, True, exception.reason
        slots = generate_slots(owner, date_obj, exception.start_time, exception.end_time, appt_type)
        return slots, True, False, exception.reason

    # 2. BlockedPeriod (Vacaciones / Cierres)
    blocked = BlockedPeriod.objects.filter(
        user=owner, 
        start_date__lte=date_obj, 
        end_date__gte=date_obj,
        is_active=True
    ).first()
    
    if blocked:
        return [], False, True, blocked.reason

    # 3. Weekly Availability
    weekday = (date_obj.weekday() + 1) % 7
    rule = AvailabilityRule.objects.filter(user=owner, weekday=weekday, is_active=True).first()
    
    if rule:
        slots = generate_slots(owner, date_obj, rule.start_time, rule.end_time, appt_type, rule.break_start, rule.break_end)
        return slots, False, False, None
    
    return [], False, False, None

def generate_slots(owner, date_obj, start, end, appt_type, break_start=None, break_end=None):
    slots = []
    duration = timedelta(minutes=appt_type.duration_minutes)
    
    current_dt = datetime.combine(date_obj, start)
    end_dt = datetime.combine(date_obj, end)
    
    now = timezone.now()
    
    while current_dt + duration <= end_dt:
        t_start = current_dt.time()
        t_end = (current_dt + duration).time()
        
        # Check for break overlap
        is_in_break = False
        if break_start and break_end:
            # Si el inicio del slot cae dentro del break
            if break_start <= t_start < break_end:
                is_in_break = True
        
        if not is_in_break and find_available_resource(appt_type, date_obj, t_start, t_end):
            slot_dt = timezone.make_aware(datetime.combine(date_obj, t_start))
            if slot_dt > now:
                slots.append(t_start.strftime('%H:%M'))
        
        current_dt += duration
        
    return slots

def find_available_resource(appt_type, date_obj, start_t, end_t):
    # Intentar obtener los recursos asignados al tipo de cita
    resources = appt_type.resources.filter(is_active=True, deleted_at__isnull=True)
    
    # Si no hay recursos asignados específicamente, buscar todos los activos del usuario
    if not resources.exists():
        from scheduler.models import Resource
        resources = Resource.objects.filter(user=appt_type.user, is_active=True, deleted_at__isnull=True)
        
    if not resources.exists():
        return None
        
    for res in resources:
        overlapping = Appointment.objects.filter(
            resource=res,
            date=date_obj,
            status='confirmed',
            start_time__lt=end_t,
            end_time__gt=start_t
        ).count()
        
        if overlapping < appt_type.slot_capacity:
            return res
    return None

def appointment_edit_view(request, token):
    appointment = get_object_or_404(Appointment, edit_token=token)
    if request.method == 'POST':
        action = request.POST.get('action')
        if action == 'cancel':
            appointment.status = 'cancelled'
            appointment.save()
            return redirect('business_landing')
    return render(request, 'booking/edit_appointment.html', {'appointment': appointment})


def appointment_ics_view(request, token):
    appointment = get_object_or_404(Appointment, edit_token=token)
    business = Business.objects.get(user=appointment.user)
    tz = business.timezone or 'America/Santiago'

    start_dt = datetime.combine(appointment.date, appointment.start_time)
    end_dt = datetime.combine(appointment.date, appointment.end_time)

    fmt = '%Y%m%dT%H%M%S'
    dtstart = start_dt.strftime(fmt)
    dtend = end_dt.strftime(fmt)
    now = timezone.now().strftime(fmt)

    lines = [
        'BEGIN:VCALENDAR',
        'VERSION:2.0',
        'PRODID:-//Citalis//Citas//ES',
        'CALSCALE:GREGORIAN',
        'METHOD:PUBLISH',
        'BEGIN:VEVENT',
        f'UID:{appointment.edit_token}@citalis.app',
        f'DTSTAMP:{now}',
        f'DTSTART:{dtstart}',
        f'DTEND:{dtend}',
        f'SUMMARY:{appointment.appointment_type.name}',
    ]

    if business.address:
        lines.append(f'LOCATION:{business.address}')

    description = f'{business.name} - {appointment.appointment_type.name}'
    if appointment.resource:
        description += f'\\nProfesional: {appointment.resource.name}'
    lines.append(f'DESCRIPTION:{description}')

    lines.extend([
        'BEGIN:VALARM',
        'TRIGGER:-PT15M',
        'ACTION:DISPLAY',
        'DESCRIPTION:Recordatorio Citalis',
        'END:VALARM',
        'END:VEVENT',
        'END:VCALENDAR',
    ])

    response = HttpResponse('\r\n'.join(lines), content_type='text/calendar; charset=utf-8')
    response['Content-Disposition'] = f'attachment; filename="cita-{appointment.edit_token}.ics"'
    return response
