package sincronizacionDatos

import (
	"context"
	"daemonService/internal/handlers"
	"daemonService/internal/models"
	"daemonService/internal/models/sincronizacionDatos/request"
	"database/sql"
	"errors"
	"fmt"
	"log"
	"net/http"
	"time"
)

type SincronizacionDatosService struct {
	models.ServiceModel
}

func (s *SincronizacionDatosService) Execute(ctx context.Context, req *http.Request, isCron bool) (interface{}, error) {

	var nit, codPuntoVenta, codSucursal, codigoSistema string

	if req != nil {
		//2) Recuperar los query params
		nit = req.URL.Query().Get("nit")
		codPuntoVenta = req.URL.Query().Get("code_point_sale")
		codSucursal = req.URL.Query().Get("code_branch")
		codigoSistema = req.URL.Query().Get("code_system")
		log.Printf("nit: %v", nit)
		log.Printf("codPuntoVenta: %v", codPuntoVenta)
		log.Printf("codSucursal: %v", codSucursal)
		log.Printf("codigoSistema: %v", codigoSistema)
	}

	// 1. Obtener datos de la base de datos
	dbCtx, dbCancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer dbCancel()

	var rows *sql.Rows
	var err error

	// Verificar si los parámetros nit, codPuntoVenta y codSucursal tienen valores
	if nit != "" && codPuntoVenta != "" && codSucursal != "" {
		// Consulta específica con los parámetros proporcionados
		query := `
        SELECT 
            r.codigo_ambiente::text, 
            r.codigo_punto_venta::text, 
            r.codigo_sistema, 
            r.codigo_sucursal::text, 
            c.cuis,
            r.nit,
            r.token_key,
            r.token_value,
            c.id
        FROM registroEmpresa r
        JOIN cuis c ON r.id = c.registro_empresa_id
        WHERE r.nit = $1 AND r.codigo_punto_venta = $2 AND r.codigo_sucursal = $3
        ORDER BY r.id`

		rows, err = s.DB.QueryContext(dbCtx, query, nit, codPuntoVenta, codSucursal)
	} else if isCron || req == nil {
		// Consulta para el caso de CRON (asumiendo que necesitas todos los registros)
		query := `
        SELECT 
            r.codigo_ambiente::text, 
            r.codigo_punto_venta::text, 
            r.codigo_sistema, 
            r.codigo_sucursal::text, 
            c.cuis,
            r.nit,
            r.token_key,
            r.token_value,
            c.id
        FROM registroEmpresa r
        JOIN cuis c ON r.id = c.registro_empresa_id
        ORDER BY r.id`

		rows, err = s.DB.QueryContext(dbCtx, query)
	} else {
		// Si no es CRON y faltan parámetros, retornar error
		return nil, fmt.Errorf("parámetros incompletos: se requiere nit, code_point_sale y code_branch")
	}

	if err != nil {
		return nil, handlers.HandleError(&s.ServiceModel, "Error en consulta SQL: %v", err)
	}
	defer rows.Close()

	var respService interface{}

	// 2. Procesar registros
	success, errors := 0, 0
	for rows.Next() {
		var solicitud request.SolicitudSincronizacion
		var cuisID int
		var tokenKey string
		var tokenValue string

		if err := rows.Scan(
			&solicitud.CodigoAmbiente,
			&solicitud.CodigoPuntoVenta,
			&solicitud.CodigoSistema,
			&solicitud.CodigoSucursal,
			&solicitud.Cuis,
			&solicitud.Nit,
			&tokenKey,
			&tokenValue,
			&cuisID,
		); err != nil {
			log.Printf("Error escaneando fila: %v", err)
			errors++
			continue
		}

		s.ServiceModel.KeyToken = tokenKey
		s.ServiceModel.ValueToken = tokenValue
		respService, err = ProcesarRegistro(&s.ServiceModel, solicitud, cuisID)
		if err != nil {
			log.Printf("Error procesando registro: %v", err)
			errors++
		} else {
			success++
		}

		fmt.Printf("respuesta del servicio: %v", respService)
	}

	if err := rows.Err(); err != nil {
		return nil, handlers.HandleError(&s.ServiceModel, "Error en resultados: %v", err)
	}

	log.Printf("Proceso completado. Éxitos: %d, Errores: %d", success, errors)
	if errors > 0 {
		return nil, fmt.Errorf("proceso completado con %d errores", errors)
	}
	return respService, nil
}

//func (s *SincronizacionDatosService) Execute(ctx context.Context, req *http.Request, isCron bool) (interface{}, error) {
//
//	//2) Recuperar los query params
//	nit := req.URL.Query().Get("nit")
//	codPuntoVenta := req.URL.Query().Get("code_point_sale")
//	codSucursal := req.URL.Query().Get("code_branch")
//	codigoSistema := req.URL.Query().Get("code_system")
//	log.Printf("ni: %v", nit)
//	log.Printf("codPuntoVenta: %v", codPuntoVenta)
//	log.Printf("codSucursal: %v", codSucursal)
//	log.Printf("codigoSistema: %v", codigoSistema)
//
//	// 1. Obtener datos de la base de datos
//	dbCtx, dbCancel := context.WithTimeout(context.Background(), 10*time.Minute)
//	defer dbCancel()
//
//	/////////  cuando es CRON = true
//	query := `
//       SELECT
//           r.codigo_ambiente::text,
//           r.codigo_punto_venta::text,
//           r.codigo_sistema,
//           r.codigo_sucursal::text,
//           c.cuis,
//           r.nit,
//           r.token_key,
//           r.token_value,
//           c.id
//       FROM registroEmpresa r
//       JOIN cuis c ON r.id = c.registro_empresa_id
//        WHERE r.nit = $1 and r.codigo_punto_venta = $2 and r.codigo_sucursal = $3
//       ORDER BY r.id`
//
//	rows, err := s.DB.QueryContext(dbCtx, query, nit, codPuntoVenta, codSucursal)
//	if err != nil {
//		return nil, handlers.HandleError(&s.ServiceModel, "Error en consulta SQL: %v", err)
//	}
//	defer rows.Close()
//
//	var respService interface{}
//
//	// 2. Procesar registros
//	success, errors := 0, 0
//	for rows.Next() {
//		var solicitud request.SolicitudSincronizacion
//		var cuisID int
//		var tokenKey string
//		var tokenValue string
//
//		if err := rows.Scan(
//			&solicitud.CodigoAmbiente,
//			&solicitud.CodigoPuntoVenta,
//			&solicitud.CodigoSistema,
//			&solicitud.CodigoSucursal,
//			&solicitud.Cuis,
//			&solicitud.Nit,
//			&tokenKey,
//			&tokenValue,
//			&cuisID,
//		); err != nil {
//			log.Printf("Error escaneando fila: %v", err)
//			errors++
//			continue
//		}
//
//		s.ServiceModel.KeyToken = tokenKey
//		s.ServiceModel.ValueToken = tokenValue
//		respService, err = ProcesarRegistro(&s.ServiceModel, solicitud, cuisID)
//		if err != nil {
//			log.Printf("Error escaneando fila: %v", err)
//		}
//
//		fmt.Printf("respuesta del servicio: %v", respService)
//	}
//
//	if err := rows.Err(); err != nil {
//		return nil, handlers.HandleError(&s.ServiceModel, "Error en resultados: %v", err)
//	}
//
//	log.Printf("Proceso completado. Éxitos: %d, Errores: %d", success, errors)
//	if errors > 0 {
//		return nil, fmt.Errorf("proceso completado con %d errores", errors)
//	}
//	return respService, nil
//}

func (s *SincronizacionDatosService) GetName() string {
	//func GetName(s models.Service) string {
	return s.Name
}

// getEmpresaYCuisID busca registroEmpresa primero por NIT y luego filtra
// por puntoVenta y/o sucursal si vienen > 0.
func getEmpresaYCuisID(db *sql.DB, nit string, puntoVenta, sucursal int) (empresaID, cuisID int, err error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	// Construyo dinámicamente el WHERE
	where := "nit = $1"
	args := []interface{}{nit}
	idx := 2

	if puntoVenta > 0 {
		where += fmt.Sprintf(" AND codigo_punto_venta = $%d", idx)
		args = append(args, puntoVenta)
		idx++
	}
	if sucursal > 0 {
		where += fmt.Sprintf(" AND codigo_sucursal = $%d", idx)
		args = append(args, sucursal)
		idx++
	}

	// Si solo vino nit, dejamos where = "nit = $1"
	query := fmt.Sprintf("SELECT id FROM registroEmpresa WHERE %s", where)
	row := db.QueryRowContext(ctx, query, args...)

	if err = row.Scan(&empresaID); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return 0, 0, fmt.Errorf("no existe registroEmpresa para %q (pv=%d, suc=%d)", nit, puntoVenta, sucursal)
		}
		return 0, 0, err
	}

	// Ahora buscamos en cuis
	row2 := db.QueryRowContext(ctx,
		`SELECT id FROM cuis WHERE registro_empresa_id = $1 ORDER BY fecha_vigencia DESC LIMIT 1`,
		empresaID,
	)
	if err = row2.Scan(&cuisID); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return empresaID, 0, fmt.Errorf("no hay CUIS para registro_empresa_id=%d", empresaID)
		}
		return empresaID, 0, err
	}

	return empresaID, cuisID, nil
}

// de sincronizar_tipo_moneda para un cuis dado.
func getRespJSONTipoMoneda(db *sql.DB, cuisID int) ([]string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	rows, err := db.QueryContext(ctx,
		`SELECT respJson
           FROM sincronizar_tipo_moneda
          WHERE cuis_id = $1`,
		cuisID,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var respList []string
	for rows.Next() {
		var resp sql.NullString
		if err := rows.Scan(&resp); err != nil {
			return nil, err
		}
		if resp.Valid {
			respList = append(respList, resp.String)
		} else {
			// si fuera NULL, podrías elegir omitirlo o añadir una cadena vacía
			respList = append(respList, "")
		}
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return respList, nil
}

//// getTipoMoneda trae todas las filas de sincronizar_tipo_moneda para un cuis dado
//func getTipoMoneda(db *sql.DB, cuisID int) ([]entities.TipoMoneda, error) {
//	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
//	defer cancel()
//
//	rows, err := db.QueryContext(ctx,
//		`SELECT id, codigo, reqSoap, respSoap, reqJson, respJson, fecha_creacion, fecha_actualizacion, cuis_id
//         FROM sincronizar_tipo_moneda
//         WHERE cuis_id = $1`,
//		cuisID,
//	)
//	if err != nil {
//		return nil, err
//	}
//	defer rows.Close()
//
//	var resultados []entities.TipoMoneda
//	for rows.Next() {
//		var tm entities.TipoMoneda
//		if err := rows.Scan(
//			&tm.ID, &tm.Codigo, &tm.ReqSoap, &tm.RespSoap,
//			&tm.ReqJson, &tm.RespJson, &tm.FechaCreacion,
//			&tm.FechaActualizacion, &tm.CUISID,
//		); err != nil {
//			return nil, err
//		}
//		resultados = append(resultados, tm)
//	}
//	if err := rows.Err(); err != nil {
//		return nil, err
//	}
//	return resultados, nil
//}
