from django.conf import settings
from num2words import num2words
from rest_framework.views import exception_handler
from rest_framework.response import Response

from datetime import date
from django.db.models import Q
from app_venin_web_new1.models import *


def gettipodoc(tipodoc):
    if tipodoc == 'FAC':
        return 1
    elif tipodoc == 'BOL':
        return 2
    elif tipodoc == 'NCR':
        return 3
    elif tipodoc == 'NDB':
        return 4
    else:
        return None

def gettipomoneda(tipomoneda):
    print(tipomoneda)
    if tipomoneda == 'S/.' or 'S/':
        return 1
    elif tipomoneda == 'USD':
        return 2
    elif tipomoneda == 'EUR':
        return 3
    else:
        return None

def gettiporetencion(tiporetencion):
    if tiporetencion == 1 or 2:
        return True
    else:
        return False
    

def gettipodocmod(tipodoc):
    if tipodoc == 'FAC':
        return 1
    elif tipodoc == 'BOL':
        return 2
    else:
        return None
  
def getfirst(string):
    try:
        return string[0]
    except:
        return ""
    
def gettipoguia(tipoguia):
    valortipodoc_guia = ""
    if tipoguia in ['T', 'E', '0']:
        valortipodoc_guia = "1"
    elif tipoguia == 'V':
        valortipodoc_guia = "2"
    return valortipodoc_guia

def numero_a_letras_con_centavos(numero):
    # Dividir la parte entera y la parte decimal
    parte_entera = int(numero)
    parte_decimal = round((numero - parte_entera) * 100)
    
    # Convertir la parte entera a letras y la parte decimal como fracción
    parte_entera_letras = num2words(parte_entera, lang='es').upper()
    parte_decimal_letras = f"{parte_decimal:02d}/100"
    
    # Formatear el resultado
    resultado = f"{parte_entera_letras} {parte_decimal_letras}"
    return resultado


def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if response is not None:
        if isinstance(response.data, list):  # Verificar si es una lista
            error_data = {"errors": response.data}  # Guardar como lista
        elif isinstance(response.data, dict):
            error_data = response.data
        else:
            error_data = {"error": "Error desconocido en el servidor"}
    else:
        error_data = {"error": "Error interno del servidor"}

    # Si estamos en modo DEBUG, mostrar más detalles del error
    if settings.DEBUG:
        error_data["exception"] = str(exc)

    return Response(error_data, status=response.status_code if response else 500)


def calcular_saldo_articulo(idarticulo, idsucursal, fecha_corte=date.today()):
    """
    Calcula el saldo de un artículo en una sucursal hasta fecha_corte (inclusive),
    teniendo en cuenta compras, ventas, notas de crédito (NCR), ajustes,
    guías de salida/entrada y órdenes de producción.
    """
    # 1. Compras (ingresos)
    compras = Detcompra.objects.filter(
        idproduct=idarticulo,
        idcompra__fecemi__lte=fecha_corte,
        idcompra__idsucursal=idsucursal
    ).exclude(idcompra__estado='ANU')

    # 2. Ventas (salidas)
    ventas = Detfactu.objects.filter(
        idproduct=idarticulo,
        idfactura__fecha__lte=fecha_corte,
        idfactura__idsucursal=idsucursal
    ).exclude(
        Q(idfactura__estado='ANU') |
        Q(idfactura__documen='NCR')
    )

    # 3. Notas de crédito (NCR) — solo documen='NCR' y sin anuladas  
    #    además excluimos ciertos motivos que no afectan saldo
    ncr = Detfactu.objects.filter(
        idproduct=idarticulo,
        idfactura__fecha__lte=fecha_corte,
        idfactura__idsucursal=idsucursal,
        idfactura__documen='NCR'
    ).exclude(
        Q(idfactura__estado='ANU') |
        Q(idfactura__motivo__in=['03', '04', '05', '08', '09', '13'])
    )

    # 4. Ajustes (entradas y salidas según tipo_ope)
    ajustes = Detajuste.objects.filter(
        idproduct=idarticulo,
        idajuste__fecha__lte=fecha_corte,
        idajuste__idsucursal=idsucursal
    ).exclude(idajuste__estado='ANU')

    # 5. Guías de salida (motivo!='01', no anuladas)
    guias_salida = Detguia.objects.filter(
        idproduct=idarticulo,
        idguiar__fecha__lte=fecha_corte,
        idguiar__idsucursal=idsucursal
    ).exclude(
        Q(idguiar__motivo__in=['01','14']) |
        Q(idguiar__estado='ANU')
    )

    # 6. Guías de entrada (sucursal destino, no anuladas)
    guias_entrada = Detguia.objects.filter(
        idproduct=idarticulo,
        idguiar__fecha__lte=fecha_corte,
        idguiar__idsucursal_destino=idsucursal
    ).exclude(idguiar__estado='ANU')

    # 7. Órdenes de producción
    op_ingresos = DetOrdenProdIngreso.objects.filter(
        idproduct=idarticulo,
        fecha__lte=fecha_corte,
        idorden__idsucursal=idsucursal
    )
    op_salidas = DetOrdenProdSalida.objects.filter(
        idproduct=idarticulo,
        idorden__fecha__lte=fecha_corte,
        idorden__idsucursal=idsucursal
    )

    # --- Cálculo acumulado ---
    saldo = 0

    # a) Compras
    saldo += sum(c.cantidad or 0 for c in compras)

    # b) Ventas
    saldo -= sum(v.cantidad or 0 for v in ventas)

    # c) Notas de crédito
    saldo += sum(n.cantidad or 0 for n in ncr)

    # d) Ajustes: motivos '05','16','17' suman, el resto restan
    for a in ajustes:
        if a.idajuste.tipo_ope in ['05', '16', '17']:
            saldo += (a.cantidad or 0)
        else:
            saldo -= (a.cantidad or 0)

    # e) Guías de salida
    saldo -= sum(g.cantidad or 0 for g in guias_salida)

    # f) Guías de entrada
    saldo += sum(g.cantidad or 0 for g in guias_entrada)

    # g) OP ingresos (producto terminado)
    saldo += sum(opi.produccion or 0 for opi in op_ingresos)

    # h) OP salidas (materia prima)
    saldo -= sum(ops.cantidad or 0 for ops in op_salidas)

    return saldo
