package app import ( "context" "fmt" "os" "os/signal" "syscall" "time" "attune-heart-therapy/internal/config" "attune-heart-therapy/internal/container" "attune-heart-therapy/internal/logger" "attune-heart-therapy/internal/server" ) // Application represents the main application type Application struct { config *config.Config container *container.Container server *server.Server log *logger.Logger } // New creates a new application instance func New() (*Application, error) { // Initialize logger first log := logger.New("application") // Load configuration cfg, err := config.Load() if err != nil { return nil, fmt.Errorf("failed to load configuration: %w", err) } // Set log level based on configuration logLevel := logger.INFO switch cfg.Logging.Level { case "DEBUG": logLevel = logger.DEBUG case "INFO": logLevel = logger.INFO case "WARN": logLevel = logger.WARN case "ERROR": logLevel = logger.ERROR case "FATAL": logLevel = logger.FATAL } logger.SetGlobalLevel(logLevel) log.Info("Application configuration loaded", map[string]interface{}{ "server_host": cfg.Server.Host, "server_port": cfg.Server.Port, "db_host": cfg.Database.Host, "db_name": cfg.Database.Name, }) // Initialize dependency injection container cont := container.New(cfg) // Initialize server srv := server.New(cfg) return &Application{ config: cfg, container: cont, server: srv, log: log, }, nil } // Initialize performs application initialization func (app *Application) Initialize() error { app.log.Info("Initializing application...") // Initialize all dependencies through the container if err := app.container.Initialize(); err != nil { return fmt.Errorf("failed to initialize dependencies: %w", err) } // Wire the container to the server app.server.SetContainer(app.container) app.log.Info("Application initialization completed successfully") return nil } // Run starts the application and handles graceful shutdown func (app *Application) Run() error { // Initialize the application if err := app.Initialize(); err != nil { return fmt.Errorf("application initialization failed: %w", err) } // Setup graceful shutdown quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // Start server in a goroutine serverErrors := make(chan error, 1) go func() { app.log.Info("Starting HTTP server...") if err := app.server.Start(); err != nil { serverErrors <- fmt.Errorf("server start failed: %w", err) } }() // Wait for either shutdown signal or server error select { case err := <-serverErrors: return err case sig := <-quit: app.log.Info("Received shutdown signal", map[string]interface{}{ "signal": sig.String(), }) } // Graceful shutdown return app.shutdown() } // shutdown performs graceful shutdown of all components func (app *Application) shutdown() error { app.log.Info("Initiating graceful shutdown...") // Create shutdown context with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() var shutdownErrors []error // Shutdown server first if app.server != nil { app.log.Info("Shutting down HTTP server...") if err := app.server.Shutdown(ctx); err != nil { app.log.Error("Error shutting down server", err) shutdownErrors = append(shutdownErrors, fmt.Errorf("server shutdown error: %w", err)) } else { app.log.Info("HTTP server shutdown completed") } } // Shutdown application dependencies if app.container != nil { app.log.Info("Shutting down application dependencies...") if err := app.container.Shutdown(); err != nil { app.log.Error("Error shutting down dependencies", err) shutdownErrors = append(shutdownErrors, err) } else { app.log.Info("Dependencies shutdown completed") } } // Wait for context deadline or completion select { case <-ctx.Done(): if ctx.Err() == context.DeadlineExceeded { app.log.Warn("Shutdown timeout exceeded, forcing exit") shutdownErrors = append(shutdownErrors, fmt.Errorf("shutdown timeout exceeded")) } default: // Shutdown completed before timeout } if len(shutdownErrors) > 0 { app.log.Error("Graceful shutdown completed with errors", nil, map[string]interface{}{ "error_count": len(shutdownErrors), }) return fmt.Errorf("shutdown completed with %d errors: %v", len(shutdownErrors), shutdownErrors) } app.log.Info("Graceful shutdown completed successfully") return nil } // GetConfig returns the application configuration func (app *Application) GetConfig() *config.Config { return app.config } // GetContainer returns the dependency injection container func (app *Application) GetContainer() *container.Container { return app.container } // HealthCheck performs a comprehensive health check func (app *Application) HealthCheck() map[string]interface{} { health := map[string]interface{}{ "status": "ok", "timestamp": time.Now().UTC().Format(time.RFC3339), "service": "Video Conference Booking System", "version": "1.0.0", } // Check container health if app.container != nil { containerHealth := app.container.HealthCheck() health["components"] = containerHealth // Update overall status based on component health if status, ok := containerHealth["status"].(string); ok && status != "ok" { health["status"] = status } } else { health["status"] = "error" health["error"] = "Container not initialized" } return health }