from django.shortcuts import render, redirect
from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
import json

from login.models import Area, Gerencia


def organigrama_view(request):
    if 'user_id' not in request.session or request.session.get('user_tipo') == 2 or request.session.get('user_tipo') == 3:
        # Redirigir al login si no hay sesión
        return redirect('/')

    # Obtener gerencias para el dropdown del editor
    gerencias_qs = Gerencia.objects.all()
    gerencias_list = list(gerencias_qs.values('id', 'nombre'))

    # Renderiza la plantilla; asegúrate de inyectar áreasDataUrl y csrfToken desde la plantilla
    return render(request, 'organigrama.html', {'gerencias': gerencias_list})


def get_areas_data(request):
    """
    Endpoint que devuelve los datos en el formato que Syncfusion UrlAdaptor espera:
    { "result": [...], "count": N }

    Acepta múltiples variantes de parámetros de paginación:
    $skip / skip / offset / start  y  $top / top / take / limit

    Si añades ?debug=1 te devolverá los parámetros que recibió (útil para verificar).
    """
    if 'user_id' not in request.session:
        return JsonResponse({'result': [], 'count': 0})

    # Aceptar múltiples nombres
    skip_raw = (request.GET.get('$skip') or request.GET.get('skip') or
                request.GET.get('offset') or request.GET.get('start'))
    top_raw = (request.GET.get('$top') or request.GET.get('top') or
               request.GET.get('take') or request.GET.get('limit'))

    # Modo debug: ver qué parámetros llegan
    if request.GET.get('debug') == '1':
        return JsonResponse({
            'debug_received_params': dict(request.GET),
            'note': 'Use this to see exact params Syncfusion sends to this endpoint'
        })

    # Query base
    queryset = Area.objects.order_by('id')
    total_count = queryset.count()

    # Intentar paginar si hay parámetros válidos
    paginated_queryset = queryset
    try:
        if skip_raw is not None and top_raw is not None:
            s = int(skip_raw)
            t = int(top_raw)
            if s < 0:
                s = 0
            if t > 0:
                paginated_queryset = queryset[s:s + t]
            # si t <= 0 -> devolver todo el queryset
    except (ValueError, TypeError):
        # Parámetros inválidos -> no paginar
        pass

    # Serializar en lista de diccionarios
    data = list(paginated_queryset.values('id', 'nombre', 'gerencia_id'))

    # Devolver en el formato esperado por Syncfusion
    response_payload = {'result': data, 'count': total_count}
    return HttpResponse(json.dumps(response_payload), content_type='application/json')


@csrf_exempt
@require_http_methods(["POST"])
def add_area(request):
    try:
        payload = json.loads(request.body.decode('utf-8') or '{}')
        data = payload.get('value') if isinstance(payload, dict) and 'value' in payload else payload
        nombre = data.get('nombre') if isinstance(data, dict) else None
        gerencia_id = data.get('gerencia_id') if isinstance(data, dict) else None

        if nombre and gerencia_id:
            try:
                gerencia = Gerencia.objects.get(id=gerencia_id)
            except Gerencia.DoesNotExist:
                return JsonResponse({'status': 'error', 'message': 'Gerencia not found'}, status=404)

            area = Area.objects.create(nombre=nombre, gerencia=gerencia)
            # Opcional: devolver el registro creado
            return JsonResponse({'status': 'success', 'result': {'id': area.id, 'nombre': area.nombre, 'gerencia_id': area.gerencia.id}})

        return JsonResponse({'status': 'error', 'message': 'Missing data'}, status=400)

    except json.JSONDecodeError:
        return JsonResponse({'status': 'error', 'message': 'Invalid JSON'}, status=400)
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)}, status=500)


@csrf_exempt
@require_http_methods(["POST"])
def update_area(request):
    """
    Espera JSON tipo batch con added/changed/deleted arrays.
    """
    try:
        payload = json.loads(request.body.decode('utf-8') or '{}')
        data = payload if isinstance(payload, dict) else {}

        processed = False
        errors = []

        # Added
        if 'added' in data and data['added']:
            for record in data['added']:
                record_id = record.pop('id', None)
                nombre = record.get('nombre')
                gerencia_id = record.get('gerencia_id')
                if nombre and gerencia_id:
                    try:
                        gerencia = Gerencia.objects.get(id=gerencia_id)
                        Area.objects.create(nombre=nombre, gerencia=gerencia)
                        processed = True
                    except Gerencia.DoesNotExist:
                        errors.append(f"Gerencia {gerencia_id} not found for added record")
                    except Exception as e:
                        errors.append(f"Error creating area: {str(e)}")
                else:
                    errors.append("Missing nombre or gerencia_id in added record")

        # Changed
        if 'changed' in data and data['changed']:
            for record in data['changed']:
                area_id = record.get('id')
                nombre = record.get('nombre')
                gerencia_id = record.get('gerencia_id')
                if area_id and nombre and gerencia_id:
                    try:
                        area = Area.objects.get(id=area_id)
                        gerencia = Gerencia.objects.get(id=gerencia_id)
                        area.nombre = nombre
                        area.gerencia = gerencia
                        area.save()
                        processed = True
                    except Area.DoesNotExist:
                        errors.append(f"Area {area_id} not found")
                    except Gerencia.DoesNotExist:
                        errors.append(f"Gerencia {gerencia_id} not found for area {area_id}")
                    except Exception as e:
                        errors.append(f"Error updating area {area_id}: {str(e)}")
                else:
                    errors.append(f"Missing id/nombre/gerencia_id in changed record: {record}")

        # Deleted
        if 'deleted' in data and data['deleted']:
            for record in data['deleted']:
                area_id = record.get('id') or record.get('key')
                if area_id:
                    try:
                        Area.objects.get(id=area_id).delete()
                        processed = True
                    except Area.DoesNotExist:
                        errors.append(f"Area {area_id} not found for deletion")
                    except Exception as e:
                        errors.append(f"Error deleting area {area_id}: {str(e)}")
                else:
                    errors.append("Missing id in deleted record")

        if processed and not errors:
            return JsonResponse({'status': 'success', 'message': 'Data saved successfully'})
        elif processed and errors:
            return JsonResponse({'status': 'partial', 'message': 'Some operations succeeded', 'errors': errors})
        else:
            return JsonResponse({'status': 'noop', 'message': 'No data to process', 'errors': errors})

    except json.JSONDecodeError:
        return JsonResponse({'status': 'error', 'message': 'Invalid JSON'}, status=400)
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)}, status=500)


@csrf_exempt
@require_http_methods(["POST"])
def delete_area(request):
    try:
        payload = json.loads(request.body.decode('utf-8') or '{}')
        area_id = payload.get('key') or payload.get('id') or payload.get('area_id')

        if area_id:
            try:
                Area.objects.get(id=area_id).delete()
                return JsonResponse({'status': 'success'})
            except Area.DoesNotExist:
                return JsonResponse({'status': 'error', 'message': 'Area not found'}, status=404)

        return JsonResponse({'status': 'error', 'message': 'Missing ID'}, status=400)

    except json.JSONDecodeError:
        return JsonResponse({'status': 'error', 'message': 'Invalid JSON'}, status=400)
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
