// @title Goyco API
// @version 0.1.0
// @description Goyco is a Y Combinator-style news aggregation platform API.
// @contact.name Goyco Team
// @contact.email sandro@cazzaniga.fr
// @license.name GPLv3
// @license.url https://www.gnu.org/licenses/gpl-3.0.html
// @host localhost:8080
// @schemes http
// @BasePath /api

package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"

	"goyco/cmd/goyco/commands"
	"goyco/docs"
	"goyco/internal/config"
	"goyco/internal/version"
)

func main() {
	loadDotEnv()

	commands.SetRunServer(runServerImpl)

	if len(os.Args) > 1 && os.Args[len(os.Args)-1] == "--daemon" {
		args := os.Args[1 : len(os.Args)-1]
		if err := commands.RunDaemonProcessDirect(args); err != nil {
			log.Fatalf("daemon error: %v", err)
		}
		return
	}

	if err := run(os.Args[1:]); err != nil {
		log.Fatalf("error: %v", err)
	}
}

func run(args []string) error {
	cfg, err := config.Load()
	if err != nil {
		return fmt.Errorf("load configuration: %w", err)
	}

	validator := commands.NewConfigValidator(nil)
	if err := validator.ValidateConfiguration(cfg); err != nil {
		return fmt.Errorf("configuration validation failed: %w", err)
	}

	docs.SwaggerInfo.Title = fmt.Sprintf("%s API", cfg.App.Title)
	docs.SwaggerInfo.Description = "Y Combinator-style news board API."
	docs.SwaggerInfo.Version = version.Version
	docs.SwaggerInfo.BasePath = "/api"
	docs.SwaggerInfo.Host = fmt.Sprintf("%s:%s", cfg.Server.Host, cfg.Server.Port)
	docs.SwaggerInfo.Schemes = []string{"http"}
	if cfg.Server.EnableTLS {
		docs.SwaggerInfo.Schemes = append(docs.SwaggerInfo.Schemes, "https")
	}

	rootFS := flag.NewFlagSet("goyco", flag.ContinueOnError)
	rootFS.SetOutput(os.Stderr)
	rootFS.Usage = printRootUsage
	showHelp := rootFS.Bool("help", false, "show this help message")
	jsonOutput := rootFS.Bool("json", cfg.CLI.JSONOutputDefault, "output results in JSON format")

	if err := rootFS.Parse(args); err != nil {
		if errors.Is(err, flag.ErrHelp) {
			return nil
		}
		return fmt.Errorf("failed to parse arguments: %w", err)
	}

	if *showHelp {
		printRootUsage()
		return nil
	}

	commands.SetJSONOutput(*jsonOutput)

	remaining := rootFS.Args()
	if len(remaining) == 0 {
		printRootUsage()
		return nil
	}

	return dispatchCommand(cfg, remaining[0], remaining[1:])
}

func dispatchCommand(cfg *config.Config, name string, args []string) error {
	switch name {
	case "run":
		return handleRunCommand(cfg, args)
	case "start":
		return commands.HandleStartCommand(cfg, args)
	case "stop":
		return commands.HandleStopCommand(cfg, args)
	case "status":
		return commands.HandleStatusCommand(cfg, name, args)
	case "user":
		return commands.HandleUserCommand(cfg, name, args)
	case "post":
		return commands.HandlePostCommand(cfg, name, args)
	case "prune":
		return commands.HandlePruneCommand(cfg, name, args)
	case "migrate", "migrations":
		return commands.HandleMigrateCommand(cfg, name, args)
	case "seed":
		return commands.HandleSeedCommand(cfg, name, args)
	case "help", "-h", "--help":
		printRootUsage()
		return nil
	default:
		printRootUsage()
		return fmt.Errorf("unknown command: %s", name)
	}
}

func handleRunCommand(cfg *config.Config, args []string) error {
	fs := newFlagSet("run", printRunUsage)
	if err := parseCommand(fs, args, "run"); err != nil {
		if errors.Is(err, commands.ErrHelpRequested) {
			return nil
		}
		return err
	}

	if fs.NArg() > 0 {
		printRunUsage()
		return errors.New("unexpected arguments for run command")
	}

	return runServer(cfg, false)
}
