// Package di provides dependency injection container and providers using uber-go/fx.
package di

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"

	"go.uber.org/fx"
)

// Container wraps the FX application and provides lifecycle management.
type Container struct {
	app *fx.App
}

// NewContainer creates a new DI container with the provided options.
func NewContainer(opts ...fx.Option) *Container {
	// Add core module
	allOpts := []fx.Option{CoreModule()}
	allOpts = append(allOpts, opts...)

	app := fx.New(allOpts...)

	return &Container{
		app: app,
	}
}

// Start starts the container and blocks until shutdown.
func (c *Container) Start(ctx context.Context) error {
	// Start the FX app
	if err := c.app.Start(ctx); err != nil {
		return err
	}

	// Wait for interrupt signal
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

	// Block until signal received
	<-sigChan

	// Create shutdown context
	shutdownCtx, cancel := context.WithTimeout(context.Background(), c.getShutdownTimeout())
	defer cancel()

	// Stop the FX app
	if err := c.app.Stop(shutdownCtx); err != nil {
		return err
	}

	return nil
}

// Stop stops the container gracefully.
func (c *Container) Stop(ctx context.Context) error {
	return c.app.Stop(ctx)
}

// getShutdownTimeout returns the shutdown timeout duration.
// Can be made configurable in the future.
func (c *Container) getShutdownTimeout() time.Duration {
	return 30 * time.Second
}
