package ipapi

import (
	"context"
	"log/slog"

	"git.eeqj.de/sneak/ipapi/internal/config"
	"git.eeqj.de/sneak/ipapi/internal/database"
	"git.eeqj.de/sneak/ipapi/internal/http"
	"git.eeqj.de/sneak/ipapi/internal/state"
	"go.uber.org/fx"
)

// Options contains all dependencies for IPAPI.
type Options struct {
	fx.In

	Config   *config.Config
	Logger   *slog.Logger
	State    *state.Manager
	Database *database.Manager
	Server   *http.Server
}

// IPAPI is the main application structure.
type IPAPI struct {
	config   *config.Config
	logger   *slog.Logger
	state    *state.Manager
	database *database.Manager
	server   *http.Server
}

// New creates a new IPAPI instance with the given options.
func New(opts Options) *IPAPI {
	return &IPAPI{
		config:   opts.Config,
		logger:   opts.Logger,
		state:    opts.State,
		database: opts.Database,
		server:   opts.Server,
	}
}

// Start initializes and starts all components.
func (i *IPAPI) Start(ctx context.Context) error {
	i.logger.Info("Starting IP API daemon",
		"port", i.config.Port,
		"state_dir", i.config.StateDir,
	)

	// Initialize state
	if err := i.state.Initialize(ctx); err != nil {
		return err
	}

	// Start database downloads in background with a fresh context
	// This avoids using the OnStart context which has a timeout
	go func() {
		dbCtx := context.Background()
		if err := i.database.EnsureDatabases(dbCtx); err != nil {
			i.logger.Error("Failed to ensure databases", "error", err)
		}
	}()

	// Start HTTP server
	return i.server.Start(ctx)
}

// Stop gracefully shuts down all components.
func (i *IPAPI) Stop(ctx context.Context) error {
	i.logger.Info("Stopping IP API daemon")

	return i.server.Stop(ctx)
}
