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 accounts.utils import data_owner
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=data_owner(request.user), deleted_at__isnull=True)
    appt_types = AppointmentType.objects.filter(user=data_owner(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=data_owner(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=data_owner(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=data_owner(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
