from server_backsemot.models import ClienteGD, Comuna, Dte, TipoCliente
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from server_backsemot.personal.personal import validaciones_basicas, buscar_personal_activo, mantener_personal_activo
from server_backsemot.personal.accionUsuario import registrar_accion
from server_backsemot.personal.plan import buscar_plan_clientepresencial_interno
from server_backsemot.utiles import Utiles
from rest_framework.decorators import api_view
from django.db.models import Q
from datetime import datetime
from environ import Env
import bcrypt
import random
import sys

env = Env()
Env.read_env()

@api_view(["POST"])
def activar_clientegd(request):
    # Validación básica
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)
    
    try:
        if not "cliente" in request.POST:
            return Utiles.responder_500("Falta el cliente a activar")
        
        desactivar = ClienteGD.objects.get(id=request.POST["cliente"])
        
        # Verificar si la cuenta ya está desactivada
        if desactivar.activo == 1:
            return Utiles.responder_500("El cliente ya se encuentra activo")
        
        # Activar la cuenta
        desactivar.activo = 1
        desactivar.save()
        mantener_personal_activo(request.POST["token"])
        #registrar_accion(request.POST["token"], 1, 57, desactivar)
        return Utiles.responder_200("Cliente activado correctamente")
    except ClienteGD.DoesNotExist:
        return Utiles.responder_500("No existe cliente con ese id")
    except Exception as e:
        return Utiles.responder_500("Error", sys.exc_info())



@api_view(["GET"])
def buscar_clientegd_id(request):
    # Busca un cliente por su id
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)

    try:
        id = request.GET.get("id")
        if not id:
            return Utiles.responder_500("Falta el id")

        c = ClienteGD.objects.get(id=id)
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Cliente encontrado", formatear_clientegd(c))
    except ClienteGD.DoesNotExist:
        return Utiles.responder_500("No existe cliente con el indicado")
    except Exception:
        return Utiles.responder_500("Error", sys.exc_info())
        
        
        
def buscar_clientegd_id_no_request(id):
    # Busca un cliente por ID
    try:
        c = ClienteGD.objects.get(id=id)
        return formatear_clientegd(c)
    
    except ClienteGD.DoesNotExist:
        return False
    except Exception:
        return False



@api_view(["GET"])
def buscar_clientegd_rut(request):
    # Busca un cliente por su RUT
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)

    try:
        rut = request.GET.get("rut")
        if not rut:
            return Utiles.responder_500("Falta el rut")

        c = ClienteGD.objects.filter(rut=rut).first()
        if not c:
            return Utiles.responder_500("No existe cliente con ese rut")
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Cliente encontrado", formatear_clientegd(c))

    except Exception:
        return Utiles.responder_500("Error", sys.exc_info())



@api_view(["GET"])
def buscar_clientegd_nombre(request):
    # Busca un cliente por nombre
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)

    try:
        nombre = request.GET.get("nombre")
        if not nombre:
            return Utiles.responder_500("Falta el nombre")

        cli = ClienteGD.objects.filter(nombre__icontains=nombre).all()
        if not cli:
            return Utiles.responder_500("No existe cliente con ese nombre")
        clientes = []
        for c in cli:
            clientes.append(formatear_clientegd(c))
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Cliente encontrado", clientes)

    except Exception:
        return Utiles.responder_500("Error", sys.exc_info())



@api_view(["GET"])
def buscar_clientegd_multiple(request):
# Busca un cliente por múltiples campos
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)

    try:
        texto = request.GET.get("texto")
        if not texto:
            return Utiles.responder_500("Falta el texto de búsqueda")

        cli = ClienteGD.objects.filter(
            Q(nombre__icontains=texto) | 
            Q(correo__icontains=texto) | 
            Q(telefono__icontains=texto) | 
            Q(rut__icontains=texto) |
            Q(giro__icontains=texto)
        ).all()
        if not cli:
            return Utiles.responder_500("No existe cliente con ese texto de búsqueda")

        clientes = [formatear_clientegd(c) for c in cli]
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Cliente encontrado", clientes)

    except Exception:
        return Utiles.responder_500("Error", sys.exc_info())
    


@api_view(["POST"])
def desactivar_clientegd(request):
    # Validación básica
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)
    
    try:
        # Verificar si se proporcionó el correo
        if not "cliente" in request.POST:
            return Utiles.responder_500("Falta el cliente a desactivar")
        
        desactivar = ClienteGD.objects.get(id=request.POST["cliente"])
        
        # Verificar si la cuenta ya está desactivada
        if desactivar.activo == 0:
            return Utiles.responder_500("El cliente ya se encuentra desactivado")
        
        # Desactivar la cuenta
        desactivar.activo = 0
        desactivar.save()
        #registrar_accion(request.POST["token"], 1, 59, desactivar)
        mantener_personal_activo(request.POST["token"])
        return Utiles.responder_200("Cliente desactivado correctamente")
    except ClienteGD.DoesNotExist:
        return Utiles.responder_500("No existe cliente con ese id")
    except Exception as e:
        return Utiles.responder_500("Error", sys.exc_info())
    



def formatear_clientegd(c: ClienteGD):
    # Formatea los datos del cliente en un diccionario
    return {
        "id": c.id,
        "rut": c.rut,
        "nombre": c.nombre,
        "direccion": c.direccion,
        "correo": c.correo,
        "telefono": c.telefono,
        "giro": c.giro,
        "comuna_id": c.comuna.id if c.comuna else None,
        "comuna_nombre": c.comuna.nombreComuna if c.comuna else None,
        "activo": c.activo,
        "tipoCliente_id": c.tipoCliente.id,
        "tipoCliente_nombre": c.tipoCliente.nombreTipoCliente
    }



@api_view(["GET"])
def listar_clientegd(request):
    # Lista todos los clientes
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)
    
    try:
        clientes = ClienteGD.objects.all().order_by("nombre")
        
        # Paginación
        page = request.GET.get('page', 1)  # Página solicitada, por defecto es 1
        paginator = Paginator(clientes, 20)  # 20 elementos por página
        
        try:
            paginated_clientes = paginator.page(page)
        except PageNotAnInteger:
            paginated_clientes = paginator.page(1)
        except EmptyPage:
            paginated_clientes = paginator.page(paginator.num_pages)
        
        # Datos de paginación
        total_items = paginator.count
        total_pages = paginator.num_pages
        current_page = paginated_clientes.number
        start_index = paginated_clientes.start_index()
        end_index = paginated_clientes.end_index()
        
        # Preparar la respuesta con los datos paginados
        datos = [formatear_clientegd(cliente) for cliente in paginated_clientes]
        
        # Respuesta final incluyendo la información de paginación
        respuesta = {
            "mensaje": "Listado clientes",
            "datos": datos,
            "paginacion": {
                "pagina_actual": current_page,
                "total_paginas": total_pages,
                "total_elementos": total_items,
                "elementos_pagina_actual": f"{start_index} al {end_index}"
            }
        }
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Listado clientes", respuesta)
    
    except Exception as e:
        return Utiles.responder_500("Error", str(e))
    


@api_view(["GET"])
def listar_clientegd_select(request):
    # Lista todos los clientes
    validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
    if validacion != "ok":
        return Utiles.responder_500(validacion)
    
    try:
        clientes = ClienteGD.objects.all().order_by("nombre")
        
        # Preparar la respuesta con los datos paginados
        datos = [formatear_clientegd(cliente) for cliente in clientes]
        
        # Respuesta final incluyendo la información de paginación
        respuesta = {
            "mensaje": "Listado clientes",
            "datos": datos,
        }
        mantener_personal_activo(request.GET["token"])
        return Utiles.responder_200("Listado clientes", respuesta)
    
    except Exception as e:
        return Utiles.responder_500("Error", str(e))
    


@api_view(["POST"])
def modificar_clientegd(request):
    try:
        # Registra un nuevo cliente
        validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
        if validacion != "ok":
            return Utiles.responder_500(validacion)
        
        p = buscar_personal_activo(token=request.POST["token"])
        if not p:
            return Utiles.responder_500("El colaborador no existe o no ha realizado el login")
    
        campos_requeridos = ["id", "rut", "nombre", "direccion", "correo", "telefono", "comuna", "tipoCliente"]
        validacion_campos = validar_campos_requeridos(request, campos_requeridos)
        if validacion_campos != "ok":
            return Utiles.responder_500(validacion_campos)
        
        id = request.POST["id"]
        try:
            cli = ClienteGD.objects.get(id=id)
        except ClienteGD.DoesNotExist:
            return Utiles.responder_500("No existe cliente con el id indicado")
        
        rut = request.POST["rut"].strip()
        nombre = request.POST["nombre"].strip()
        direccion = request.POST["direccion"].strip()
        correo = request.POST["correo"].strip()
        telefono = request.POST["telefono"].strip()
        comuna = request.POST["comuna"]
        tcliente = request.POST["tipoCliente"]

        if not Utiles.validate_rut(rut):
            return Utiles.responder_500("Rut no válido")
        if not Utiles.valida_email(correo):
            return Utiles.responder_500("Correo no válido")
        if not Utiles.valida_telefono(telefono):
            return Utiles.responder_500("Teléfono no válido")

        # Validar unicidad sin contar el cliente actual
        if ClienteGD.objects.filter(rut=rut).exclude(id=cli.id).exists():
            return Utiles.responder_500("Ya existe otro cliente con este RUT")
        if ClienteGD.objects.filter(correo=correo).exclude(id=cli.id).exists():
            return Utiles.responder_500("Ya existe otro cliente con este correo")
        
        if int(tcliente) != 1 and int(tcliente) != 2:
            return Utiles.responder_500("Valor de tipo cliente incorrecto")
        if int(tcliente) == 2:
            if not "giro" in request.POST:
                return Utiles.responder_500("Falta el giro")
            else:
                giro = request.POST["giro"]
                if len(giro) > 40:
                    return Utiles.responder_500("El largo máximo del giro es de 40 caracteres")
        
        resp, plan = buscar_plan_clientepresencial_interno()
        if not resp:
            return Utiles.responder_500(plan)

        comu = Comuna.objects.get(id=comuna)
        tc = TipoCliente.objects.get(id=tcliente)

        cli.rut = rut
        cli.nombre = nombre
        cli.direccion = direccion
        cli.correo = correo
        cli.telefono = telefono
        cli.comuna = comu
        cli.tipoCliente = tc
        if int(tcliente) == 2:
            cli.giro = giro
        cli.save()
        #registrar_accion(request.POST["token"], 1, 61, cli)
        mantener_personal_activo(request.POST["token"])
        return Utiles.responder_200("Cliente modificado correctamente")
    except Comuna.DoesNotExist:
        return Utiles.responder_500("No existe comuna con ese id")
    except Dte.DoesNotExist:
        return Utiles.responder_500("No existe DTE con ese id")
    except TipoCliente.DoesNotExist:
        return Utiles.responder_500("No existe tipo cliente con ese id")
    except:
        return Utiles.responder_500("Error", sys.exc_info())



@api_view(["POST"])
def registrar_clientegd(request):
    try:
        # Registra un nuevo cliente
        validacion = validaciones_basicas(validaciones=[1, 2, 3, 4], perfiles=[1, 2, 3], request=request)
        if validacion != "ok":
            return Utiles.responder_500(validacion)
        
        p = buscar_personal_activo(token=request.POST["token"])
        if not p:
            return Utiles.responder_500("El colaborador no existe o no ha realizado el login")
    
        campos_requeridos = ["rut", "nombre", "direccion", "correo", "telefono", "comuna", "tipoCliente"]
        validacion_campos = validar_campos_requeridos(request, campos_requeridos)
        if validacion_campos != "ok":
            return Utiles.responder_500(validacion_campos)
        
        rut = request.POST["rut"].strip()
        nombre = request.POST["nombre"].strip()
        direccion = request.POST["direccion"].strip()
        correo = request.POST["correo"].strip()
        telefono = request.POST["telefono"].strip()
        comuna = request.POST["comuna"]
        tcliente = request.POST["tipoCliente"]

        if not Utiles.validate_rut(rut):
            return Utiles.responder_500("Rut no válido")
        if not Utiles.valida_email(correo):
            return Utiles.responder_500("Correo no válido")
        if not Utiles.valida_telefono(telefono):
            return Utiles.responder_500("Teléfono no válido")

        # Validar unicidad de RUT y correo
        if ClienteGD.objects.filter(rut=rut).exists():
            return Utiles.responder_500("Ya existe un cliente con este RUT")
        if ClienteGD.objects.filter(correo=correo).exists():
            return Utiles.responder_500("Ya existe un cliente con este correo")

        if int(tcliente) != 1 and int(tcliente) != 2:
            return Utiles.responder_500("Valor de tipo cliente incorrecto")
        if int(tcliente) == 2:
            if not "giro" in request.POST:
                return Utiles.responder_500("Falta el giro")
            else:
                giro = request.POST["giro"]
                if len(giro) > 40:
                    return Utiles.responder_500("El largo máximo del giro es de 40 caracteres")
        

        comu = Comuna.objects.get(id=comuna)
        tc = TipoCliente.objects.get(id=tcliente)

        cli = ClienteGD()
        cli.rut = rut
        cli.nombre = nombre
        cli.direccion = direccion
        cli.correo = correo
        cli.telefono = telefono
        cli.comuna = comu
        cli.tipoCliente = tc
        if int(tcliente) == 2:
            cli.giro = giro
        cli.save()
        #registrar_accion(request.POST["token"], 1, 60, cli)
        mantener_personal_activo(request.POST["token"])
        return Utiles.responder_200("Se ha registrado el cliente")
    except Comuna.DoesNotExist:
        return Utiles.responder_500("No existe comuna con ese id")
    except Dte.DoesNotExist:
        return Utiles.responder_500("No existe DTE con ese id")
    except TipoCliente.DoesNotExist:
        return Utiles.responder_500("No existe tipo cliente con ese id")
    except:
        return Utiles.responder_500("Error", sys.exc_info())


    

def buscar_clientegd_activo(token):
    try:
        # Buscar personal activo
        personal = ClienteGD.objects.filter(token=token, activo=1).first()
        return personal
    except Exception:
        return Utiles.responder_500("Error", sys.exc_info())
    


def validar_campos_requeridos(request, campos):
    # Valida que los campos requeridos estén presentes y no sean nulos o vacíos en la solicitud (POST o GET)
    for campo in campos:
        valor_post = request.POST.get(campo, "").strip()
        valor_get = request.GET.get(campo, "").strip()
        
        if not valor_post and not valor_get:
            return f"Falta {campo}"
        
    return "ok"