package cmd

import (
	"context"
	"strings"

	"github.com/go-shiori/shiori/internal/config"
	"github.com/go-shiori/shiori/internal/http"
	"github.com/go-shiori/shiori/internal/model"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newServerCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "server",
		Short: "Starts the Shiori webserver",
		Long:  "Serves the Shiori web interface and API.",
		Run:   newServerCommandHandler(),
	}

	cmd.Flags().IntP("port", "p", 8080, "Port used by the server")
	cmd.Flags().StringP("address", "a", "", "Address the server listens to")
	cmd.Flags().StringP("webroot", "r", "/", "Root path that used by server")
	cmd.Flags().Bool("access-log", false, "Print out a non-standard access log")
	cmd.Flags().Bool("serve-web-ui", true, "Serve static files from the webroot path")
	cmd.Flags().String("secret-key", "", "Secret key used for encrypting session data")

	return cmd
}

func setIfFlagChanged(flagName string, flags *pflag.FlagSet, cfg *config.Config, fn func(cfg *config.Config)) {
	if flags.Changed(flagName) {
		fn(cfg)
	}
}

func newServerCommandHandler() func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		ctx := context.Background()

		// Get flags values
		port, _ := cmd.Flags().GetInt("port")
		address, _ := cmd.Flags().GetString("address")
		rootPath, _ := cmd.Flags().GetString("webroot")
		accessLog, _ := cmd.Flags().GetBool("access-log")
		serveWebUI, _ := cmd.Flags().GetBool("serve-web-ui")
		secretKey, _ := cmd.Flags().GetBytesHex("secret-key")

		cfg, dependencies := initShiori(ctx, cmd)

		// Validate root path
		if rootPath == "" {
			rootPath = "/"
		}

		if !strings.HasPrefix(rootPath, "/") {
			rootPath = "/" + rootPath
		}

		if !strings.HasSuffix(rootPath, "/") {
			rootPath += "/"
		}

		// Override configuration from flags if needed
		setIfFlagChanged("port", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.Port = port
		})
		setIfFlagChanged("address", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.Address = address + ":"
		})
		setIfFlagChanged("webroot", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.RootPath = rootPath
		})
		setIfFlagChanged("access-log", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.AccessLog = accessLog
		})
		setIfFlagChanged("serve-web-ui", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.ServeWebUI = serveWebUI
		})
		setIfFlagChanged("secret-key", cmd.Flags(), cfg, func(cfg *config.Config) {
			cfg.Http.SecretKey = secretKey
		})

		dependencies.Log.Infof("Starting Shiori v%s", model.BuildVersion)

		server, err := http.NewHttpServer(dependencies.Log).Setup(cfg, dependencies)
		if err != nil {
			dependencies.Log.WithError(err).Fatal("error setting up server")
		}

		if err := server.Start(ctx); err != nil {
			dependencies.Log.WithError(err).Fatal("error starting server")
		}
		dependencies.Log.WithField("addr", address).Debug("started http server")

		server.WaitStop(ctx)
	}
}
