package app

import (
	"context"
	"fmt"

	"github.com/giantswarm/muster/internal/config"
	"github.com/giantswarm/muster/pkg/logging"
)

// Application represents the main application structure that bootstraps and runs muster.
// It encapsulates all necessary configuration and services required for the application's
// lifecycle, including initialization, service management, and execution mode handling.
//
// The Application follows a two-phase initialization pattern:
//  1. Bootstrap phase: Load configuration, initialize logging, setup services
//  2. Execution phase: Run the orchestrator
//
// Example usage:
//
//	cfg := app.NewConfig(true, false, "")  // debug enabled
//	app, err := app.NewApplication(cfg)
//	if err != nil {
//	    return fmt.Errorf("failed to create application: %w", err)
//	}
//	return app.Run(ctx)
type Application struct {
	config   *Config
	services *Services
}

// NewApplication creates and initializes a new application instance with the provided configuration.
// This function performs the complete bootstrap sequence:
//
//  1. Configures logging based on debug settings
//  2. Loads muster configuration (layered or single-path)
//  3. Initializes all required services and API handlers
//  4. Sets up service dependencies and registrations
//
// Configuration Loading Behavior:
//   - If cfg.ConfigPath is set: loads from the specified directory only
//   - If cfg.ConfigPath is empty: uses layered loading (defaults + user + project)
//
// The function returns an error if any critical initialization step fails,
// including configuration loading or service initialization failures.
//
// Example:
//
//	cfg := app.NewConfig(true, false, "/custom/config")  // CLI mode, custom config
//	app, err := app.NewApplication(cfg)
//	if err != nil {
//	    log.Fatalf("Bootstrap failed: %v", err)
//	}
func NewApplication(cfg *Config) (*Application, error) {
	// Augment the system trust pool before any HTTP client is constructed.
	if cfg.ExtraCAFile != "" {
		if err := installExtraCAFile(cfg.ExtraCAFile); err != nil {
			logging.Error("Bootstrap", err, "Failed to install extra CA file")
			return nil, fmt.Errorf("install extra CA file: %w", err)
		}
	}

	// Load environment configuration
	var musterCfg config.MusterConfig
	var err error

	if cfg.ConfigPath == "" {
		panic("Logic error: empty ConfigPath")
	}

	musterCfg, err = config.LoadConfig(cfg.ConfigPath)
	if err != nil {
		logging.Error("Bootstrap", err, "Failed to load muster configuration from path: %s", cfg.ConfigPath)
		return nil, fmt.Errorf("failed to load muster configuration from path %s: %w", cfg.ConfigPath, err)
	}

	cfg.MusterConfig = &musterCfg

	// Initialize services
	services, err := InitializeServices(cfg)
	if err != nil {
		logging.Error("Bootstrap", err, "Failed to initialize services")
		return nil, fmt.Errorf("failed to initialize services: %w", err)
	}

	return &Application{
		config:   cfg,
		services: services,
	}, nil
}

// Run executes the application
//
// Handles graceful shutdown via context cancellation and system signals.
// The method blocks until the application is terminated or encounters an error.
//
// Returns an error if the selected execution mode fails to start or encounters
// a runtime error during execution.
func (a *Application) Run(ctx context.Context) error {
	return runOrchestrator(ctx, a.services)
}
