package main

import (
	"flag"
	"log"
	"os"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/pyroscope-io/pyroscope/pkg/agent/profiler"
	"github.com/sujit-baniya/fiber-boilerplate/app"
	"github.com/sujit-baniya/fiber-boilerplate/config"
	"github.com/sujit-baniya/fiber-boilerplate/migrations"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
	"github.com/sujit-baniya/fiber-boilerplate/rest/routes"
	"github.com/sujit-baniya/fiber-boilerplate/utils"
)

func main() {
	configFile := flag.String("config", "config.yml", "User Config file from user")
	migrate := flag.Bool("migrate", false, "Update db structure")
	flag.Parse()

	// Cargar configuración
	app.Load(*configFile)

	// Configurar Pyroscope profiler
	if app.Http.Profiler.Enabled {
		_, _ = profiler.Start(profiler.Config{
			ApplicationName: app.Http.Server.Name,
			ServerAddress:   app.Http.Profiler.Server,
		})
	}

	// Actualizar versión del servidor
	app.Http.Server.Version = app.Version

	// Los archivos de /uploads dejan de ser públicos: solo se sirven a usuarios
	// con sesión iniciada en el panel. Los clientes del portal siguen bajando sus
	// documentos por los endpoints dedicados, que validan que les pertenezcan.
	config.UploadsGuard = func(c *fiber.Ctx) bool {
		return auth.IsLoggedIn(c)
	}

	// Habilitar CORS
	app.Http.Server.App.Use(cors.New(cors.Config{
		AllowOrigins: "*",
		AllowMethods: "GET,POST,PUT,DELETE,OPTIONS",
		AllowHeaders: "Content-Type, Authorization",
	}))

	if *migrate {
		// Ejecutar migraciones
		migrations.Migrate()
	} else {
		// Crear/actualizar tablas de Renovaciones e idempotente)
		migrations.MigrateRenovaciones()
		// Crear/actualizar tablas de Portal, Telegram y Proyectos
		migrations.MigratePortal()
		// Crear tabla de Landing Generator
		migrations.MigrateLanding()
		// Crear tablas de integraciones y pasarelas si no existen.
		// AutoMigrate(a, b, c...) se detiene en el primer modelo que falle: todo lo
		// que viene después en la lista se queda sin tabla, en silencio (fue la
		// causa real de que plantillas_documento/tarifas desaparecieran de
		// producción — un modelo antes en la lista falló y todo lo posterior no se
		// llegó a crear). Migrando uno por uno, un modelo roto no bloquea al resto.
		modelosBase := []interface{}{
			// Tablas base del sistema (columnas nuevas)
			&models.Users{},
			&models.Roles{},
			&models.Submodules{},
			&models.QueryHistory{},
			&models.OssApi{},
			&models.QrVcard{},
			&models.VcfVcard{},
			&models.HostingerConfig{},
			&models.CloudflareConfig{},
			&models.BoldConfig{},
			&models.BoldWebhookLog{},
			&models.BoldCallbackLog{},
			&models.DlocalPaymentLog{},
			// Documentación por SaaS
			&models.SaasProducto{},
			&models.DocCategoria{},
			&models.DocPagina{},
			// Integraciones SaaS (dispatcher de pagos)
			&models.SaasApiConfig{},
			&models.SaasDispatchLog{},
			// Notificaciones
			&models.NotifEventoConfig{},
			&models.SistemaNotificacion{},
			&models.ServidorAlertaUmbral{},
			// Shield
			&models.ShieldConfig{},
			// Partner
			&models.PartnerRecurso{},
			&models.PartnerComunicado{},
			// Portal: recuperación de contraseña
			&models.PortalPasswordResetToken{},
			// Integración VCard API Admin
			&models.VcardApiConfig{},
			// Integración Coolify (multi-instancia)
			&models.CoolifyConfig{},
			// AI Config: campos del agente Telegram
			&models.AiConfig{},
			// Agente Telegram: historial y chats autorizados
			&models.TelegramAgentHistory{},
			&models.TelegramAgentAuth{},
			// Servidores: nuevos campos de agente + tabla join de integraciones
			&models.Servidor{},
			&models.ConxDb{},
			&models.ProvServidor{},
			// SMTP
			&models.SmtpConfig{},
			// WebSMS (LabsMobile)
			&models.WebSmsConfig{},
			&models.WebSmsLog{},
			&models.WebSmsWebhookLog{},
			// Contabilidad
			&models.Cuenta{},
			&models.Entidad{},
			&models.Transaccion{},
			&models.CuentaCobro{},
			&models.CuentaPagar{},
			&models.ConsolidadoMensual{},
			// Historial de métricas del agente
			&models.ServidorMetricasHistory{},
			// Monitor de disponibilidad de URLs
			&models.UrlMonitor{},
			&models.UrlMonitorLog{},
			// Tablero de tareas
			&models.Tarea{},
			&models.TareaComentario{},
			// Pagos externos: API de cobros para aplicaciones de terceros
			&models.ServicioPagoExterno{},
			&models.SolicitudPagoExterna{},
			// Soporte: webhook de correo entrante
			&models.SoporteWebhookConfig{},
			// Automatización de cotizaciones, contratos, actas y cuentas de cobro con IA
			&models.PlantillaDocumento{},
			&models.Tarifa{},
			&models.DocumentoGenerado{},
			&models.Arquitectura{},
			// Vinculación de Telegram para staff interno
			&models.TelegramStaffToken{},
			// uMind: chat con IA embebible por tenant (widget web + RAG)
			&models.UmindTenant{},
			&models.UmindAgente{},
			&models.UmindDocumento{},
			&models.UmindChunk{},
			&models.UmindMensaje{},
			&models.UmindHerramienta{},
			&models.UmindCanal{},
			&models.UmindConexion{},
			&models.UmindEventoLog{},
			&models.UmindPlan{},
			// API Keys de /api/v2 (token + IP obligatoria + scopes)
			&models.ApiKey{},
			// Integraciones: OCR y transcripción de audio (servicios propios)
			&models.OcrConfig{},
			&models.WhisperAsrConfig{},
		}
		for _, m := range modelosBase {
			if err := app.Http.Database.DB.AutoMigrate(m); err != nil {
				log.Printf("[MIGRATE] Error migrando %T: %v", m, err)
			}
		}
		// Seed automático (idempotente) de módulos del sistema
		migrations.SeedRenovaciones()
		migrations.SeedIntegraciones()
		migrations.SeedPasarelas()
		migrations.SeedSaas()
		migrations.SeedServidores()
		migrations.SeedAdministracion()
		migrations.SeedPlantillasBase()
		migrations.SeedTelegram()
		migrations.SeedPortalClientes()
		migrations.SeedNotifDefaults()
		migrations.SeedShield()
		migrations.SeedPartnerRecursos()
		models.SeedContabilidad()
		// SeedBalanceData carga transacciones contables reales de 2026. Ya no se
		// ejecuta en cada arranque: si el contador editaba o borraba una de esas
		// filas, el siguiente reinicio la recreaba y el balance quedaba duplicado.
		// Para recargarla puntualmente: SEED_BALANCE=1 ./apiv2
		if os.Getenv("SEED_BALANCE") == "1" {
			log.Println("[SEED] SEED_BALANCE=1 — cargando datos de balance")
			models.SeedBalanceData()
		}
		migrations.SeedContabilidadMenu()
		migrations.SeedWebSms()
		migrations.SeedUrlMonitor()
		migrations.SeedTareas()
		migrations.SeedPagosExternos()
		migrations.SeedAutomatizacionIA()
		migrations.SeedUmind()
		migrations.MigrarUmindAgentes()
		migrations.SeedApiKeys()
		if n, err := models.RepararEstadosTareaInvalidos(); err != nil {
			log.Printf("[FIX] Error reparando estados de tareas: %v", err)
		} else if n > 0 {
			log.Printf("[FIX] %d tarea(s) con estado inválido reparadas (ahora visibles en el Kanban)", n)
		}
		// Cargar config SMTP desde BD (sobreescribe valores del .env/config.yml si hay registro activo)
		if smtpCfg, err := models.GetSmtpConfig(); err == nil {
			app.Http.Mail.Host = smtpCfg.Host
			app.Http.Mail.Port = smtpCfg.Port
			app.Http.Mail.Username = smtpCfg.Username
			app.Http.Mail.Password = utils.Decrypt(smtpCfg.Password, app.Http.Server.Key)
			app.Http.Mail.Encryption = smtpCfg.Encryption
			app.Http.Mail.FromAddress = smtpCfg.FromAddress
			app.Http.Mail.FromName = smtpCfg.FromName
			app.Http.Mail.SetupMailer()
			log.Println("[SMTP] Configuración cargada desde base de datos")
		} else {
			log.Println("[SMTP] Sin config en BD, usando valores del entorno")
		}
		// Iniciar cron de vencimientos
		services.IniciarCron()
		defer services.DetenerCron()
		// Cargar rutas
		routes.LoadRoutes(app.Http.Server.App)
		app.Http.Route404()
		log.Fatal(app.Http.Server.ServeWithGraceFullShutdown())
	}
}
