package main

import (
	"context"
	"daemonService/internal/handlers"
	"daemonService/internal/models"
	svc "daemonService/internal/models"
	"daemonService/internal/models/obtencionCodigos"
	"daemonService/internal/repositories"
	"daemonService/internal/services/obtencionCodigo"
	"daemonService/internal/services/procesar"
	"daemonService/internal/services/sincronizacionDatos"
	"flag"
	"fmt"
	"github.com/robfig/cron/v3"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"daemonService/internal/api"
	"daemonService/internal/config"
	"daemonService/internal/database"
	"daemonService/internal/notifications"
	"daemonService/internal/services"
)

func main() {
	configFile := flag.String("config", "configs/config.yaml", "Ruta al archivo de configuración")
	runOnce := flag.Bool("run-once", false, "Ejecutar servicios una vez y salir")
	serviceName := flag.String("service", "", "Nombre del servicio específico a ejecutar")
	flag.Parse()

	// Cargar configuración
	cfg, err := config.LoadConfig(*configFile)
	if err != nil {
		log.Fatalf("Error al cargar configuración: %v", err)
	}

	// Inicializar la base de datos
	db, err := database.InitDB(*cfg)
	if err != nil {
		log.Fatalf("Error al inicializar la base de datos: %v", err)
	}
	defer db.Close()

	// Crear sistema de notificaciones
	notifier := notifications.CreateNotificationSender(cfg.Notifications.Enabled, cfg.Notifications.Method, cfg.Notifications.Config)
	if notifier != nil {
		log.Printf("Sistema de notificaciones iniciado: %s", cfg.Notifications.Method)
	}
	// Crear servicios a partir de la configuración
	var servicesList []models.SoapService
	var servicesList2 []obtencionCodigos.CuisService
	for _, svcCfg := range cfg.Services {
		if !svcCfg.Enabled {
			continue
		}
		// Crear el logger para el servicio
		serviceLogger := log.New(log.Writer(), fmt.Sprintf("[%s] ", svcCfg.Name), log.LstdFlags)
		baseSvc := svc.ServiceModel{
			Name:               svcCfg.Name,
			Enabled:            svcCfg.Enabled,
			Concurrency:        svcCfg.Concurrency,
			DB:                 db,
			SOAPEndpoint:       cfg.SOAP.FACTURA_SINCRONIZACION.Endpoint,
			SOAPTimeout:        time.Duration(cfg.SOAP.FACTURA_SINCRONIZACION.Timeout) * time.Second,
			SOAPRetries:        cfg.SOAP.FACTURA_SINCRONIZACION.Retries,
			NotificationSender: notifier,
			KeyToken:           "",
			ValueToken:         "",
			TagNames:           "",
			QueryInsert:        "",
			MsgCustomResponse:  "",
		}

		cuisServiceModel := obtencionCodigos.CuisServiceModel{
			Name:               svcCfg.Name,
			Enabled:            svcCfg.Enabled,
			Concurrency:        svcCfg.Concurrency,
			DB:                 db,
			SOAPEndpoint:       cfg.SOAP.FACTURA_CODIGO.Endpoint,
			SOAPTimeout:        time.Duration(cfg.SOAP.FACTURA_CODIGO.Timeout) * time.Second,
			SOAPRetries:        cfg.SOAP.FACTURA_CODIGO.Retries,
			NotificationSender: notifier,
			TokenKey:           "",
			TokenValue:         "",
			TagNames:           "",
			TagNamesCufd:       "",
			QueryInsert:        "",
			MsgCustomResponse:  "",
		}

		//registrar-empresa solo para registrar empresa
		cuisServiceModel.TagNames = "cuis"
		cuisServiceModel.TagNamesCufd = "cufd"
		cuisServiceModel.QueryInsert = "INSERT INTO registroEmpresa (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
		cuisServiceModel.MsgCustomResponse = "Registrar Empresa"

		procesarRegistro := procesar.NewProcesarRegistro(cuisServiceModel)
		empresaRepository := repositories.NewEmpresaRepository(cuisServiceModel)
		cuisService := services.NewCuisService(cuisServiceModel, serviceLogger)
		cuisRepository := repositories.NewCuisRepository(baseSvc, cuisService)
		cronHandler := handlers.NewCronHandler(cuisService, empresaRepository, cuisRepository, procesarRegistro)
		apiHandler := handlers.NewApiHandler(cuisService, cuisRepository, procesarRegistro)

		// Llamar a NewObtencionCodigoService correctamente
		obtencionCodigoSvc := obtencionCodigo.NewObtencionCodigoService(
			cuisServiceModel,
			cuisService,
			cronHandler,
			apiHandler,
		)

		switch svcCfg.Name {
		case "registrar-empresa":
			servicesList2 = append(servicesList2, obtencionCodigoSvc)
			break
		case "actividades": //todo revisar que pasa
			baseSvc.TagNames = "sincronizarActividades"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_actividades (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado de Actividades"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "sincronizar_fecha_hora": //todo revisar que pasa
			baseSvc.TagNames = "sincronizarFechaHora"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_fecha_hora (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Sincronizar la hora"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "sincronizar_mensaje_servicio": //todo revisar que pasa
			baseSvc.TagNames = "sincronizarListaMensajesServicios"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_mensaje_servicio (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Sincronizar mensaje servicio"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "leyendas_factura":
			baseSvc.TagNames = "sincronizarListaLeyendasFactura"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_leyendas_factura (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado Leyendas de Facturas"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "producto-servicio":
			baseSvc.TagNames = "sincronizarListaProductosServicios"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_productos_servicios (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado Producto Servicio"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_motivo_anulacion":
			baseSvc.TagNames = "sincronizarParametricaMotivoAnulacion"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_motivo_anulacion (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado motivo anulacion"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_documento_identidad":
			baseSvc.TagNames = "sincronizarParametricaTipoDocumentoIdentidad"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_documento_identidad (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de documento de identidad"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_documento_sector":
			baseSvc.TagNames = "sincronizarParametricaTipoDocumentoSector"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_documento_sector (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de documento sector"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_emision": //todo falta este
			baseSvc.TagNames = "sincronizarParametricaTipoEmision"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_emision (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de emision"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_actividades_documento_sector": //todo falta este
			baseSvc.TagNames = "sincronizarListaActividadesDocumentoSector"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_actividades_documento_sector (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de emision"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_metodo_pago":
			baseSvc.TagNames = "sincronizarParametricaTipoMetodoPago"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_metodo_pago (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos metodo de pago"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_moneda":
			baseSvc.TagNames = "sincronizarParametricaTipoMoneda"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_moneda (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de moneda"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_punto_venta":
			baseSvc.TagNames = "sincronizarParametricaTipoPuntoVenta"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_punto_venta (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de punto de venta"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_factura": //todo este falta
			baseSvc.TagNames = "sincronizarParametricaTiposFactura"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_factura (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de factura"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_unidad_medida":
			baseSvc.TagNames = "sincronizarParametricaUnidadMedida"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_tipo_unidad_medida (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado tipos de unidad de medida"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "tipo_evento_significativos":
			baseSvc.TagNames = "sincronizarParametricaEventosSignificativos"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_evento_significativo (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado eventos significativos"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "sincronizar_tipo_habitacion":
			baseSvc.TagNames = "sincronizarParametricaTipoHabitacion"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_Tipo_Habitacion (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado eventos significativos"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		case "sincronizar_pais_origen":
			baseSvc.TagNames = "sincronizarParametricaPaisOrigen"
			baseSvc.QueryInsert = "INSERT INTO sincronizar_Pais_Origen (codigo, reqSoap, respSoap, reqJson, respJson, cuis_id, fecha_creacion) VALUES ($1, $2, $3, $4, $5, $6, NOW() AT TIME ZONE 'America/La_Paz') ON CONFLICT (codigo, cuis_id) DO UPDATE SET reqSoap = EXCLUDED.reqSoap, respSoap = EXCLUDED.respSoap, reqJson = EXCLUDED.reqJson, respJson = EXCLUDED.respJson, cuis_id = EXCLUDED.cuis_id, fecha_actualizacion = NOW() AT TIME ZONE 'America/La_Paz';"
			baseSvc.MsgCustomResponse = "Listado eventos significativos"
			servicesList = append(servicesList, &sincronizacionDatos.SincronizacionDatosService{
				ServiceModel: baseSvc,
			})
			break
		default:
			log.Printf("Servicio desconocido: %s", svcCfg.Name)
		}
	}

	// Si se especifica un servicio específico, filtrar la lista.
	if *serviceName != "" {
		var filtered []models.SoapService
		for _, s := range servicesList {
			if s.GetName() == *serviceName {
				filtered = append(filtered, s)
				break
			}
		}
		if len(filtered) == 0 {
			log.Fatalf("No se encontró el servicio: %s", *serviceName)
		}
		servicesList = filtered
		log.Printf("Ejecutando solo el servicio: %s", *serviceName)
	}

	// Crear contexto con cancelación para manejar señales de terminación.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Canal para capturar señales del sistema.
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	// Iniciar servidor HTTP si se configura puerto para API.
	var httpServer *http.Server
	if cfg.API.Port > 0 {
		httpServer = api.StartAPIServer(cfg.API.Port, servicesList, servicesList2, false)
	}

	// Goroutine para manejar señales.
	go func() {
		sig := <-sigChan
		log.Printf("Recibida señal: %v. Cerrando...", sig)
		if notifier != nil {
			notifier.SendNotification("Servicio detenido", fmt.Sprintf("El servicio fue detenido por la señal: %v", sig))
		}
		cancel()
		if httpServer != nil {
			log.Println("Cerrando servidor HTTP...")
			shutdownCtx, cancelServer := context.WithTimeout(context.Background(), 10*time.Second)
			defer cancelServer()
			if err := httpServer.Shutdown(shutdownCtx); err != nil {
				log.Printf("Error al cerrar servidor HTTP: %v", err)
			}
		}
	}()

	// Si se debe ejecutar solo una vez.
	if *runOnce {
		errors := services.RunAllServices(ctx, servicesList, false)
		if len(errors) > 0 {
			for _, e := range errors {
				log.Printf("Error: %v", e)
			}
			os.Exit(1)
		}
		return
	}

	// Configurar primer cron
	c := cron.New(cron.WithSeconds())
	_, err = c.AddFunc(cfg.Schedule.FACTURA_SINCRONIZACION.Cron, func() {
		log.Println("Iniciando ejecución programada de servicios")
		execCtx, execCancel := context.WithCancel(ctx)
		defer execCancel()

		errors := services.RunAllServices(execCtx, servicesList, true)
		if len(errors) > 0 {
			errMsg := "Errores durante la ejecución programada:"
			for _, err := range errors {
				errMsg += "\n- " + err.Error()
			}
			if notifier != nil {
				notifier.SendNotification("Errores en ejecución programada", errMsg)
			}
			log.Println(errMsg)
		} else {
			log.Println("Ejecución programada completada exitosamente")
		}
	})

	if err != nil {
		log.Fatalf("Error al programar tareas: %v", err)
	}

	// Configurar segundo cron
	cronGetCode := cron.New(cron.WithSeconds())
	_, err = cronGetCode.AddFunc(cfg.Schedule.FACTURA_CODIGO.Cron, func() {
		log.Println("Iniciando ejecución programada para Obtener Codigos")
		execCtx, cancel := context.WithCancel(context.Background())
		defer cancel()
		//execCtx, execCancel := context.WithCancel(ctx)
		//defer execCancel()

		errors := services.RunAllGetCodeServices(execCtx, servicesList2, true)
		if len(errors) > 0 {
			errMsg := "Errores durante la ejecución programada Obtener Codigos:"
			for _, err := range errors {
				errMsg += "\n- " + err.Error()
			}
			if notifier != nil {
				notifier.SendNotification("Errores en ejecución programada Obtener Codigos", errMsg)
			}
			log.Println(errMsg)
		} else {
			log.Println("Ejecución programada completada exitosamente Obtener Codigos")
		}
	})

	if err != nil {
		log.Fatalf("Error al programar tareas Obtener Codigos: %v", err)
	}

	// Iniciar ambos cron
	c.Start()
	cronGetCode.Start()

	log.Printf("Demonio de servicios iniciado. Programación: %s", cfg.Schedule.FACTURA_SINCRONIZACION.Cron)
	log.Printf("Demonio de obtención de códigos iniciado. Programación: %s", cfg.Schedule.FACTURA_CODIGO.Cron)

	if notifier != nil {
		notifier.SendNotification("Servicios iniciados",
			fmt.Sprintf("Los servicios SOAP han sido iniciados con programación: %s", cfg.Schedule.FACTURA_SINCRONIZACION.Cron))
	}

	// Esperar a que el contexto termine y luego detener ambos cron
	<-ctx.Done()
	c.Stop()
	cronGetCode.Stop()
	log.Println("Demonios detenidos correctamente")
}
