package main

import (
	"context"
	"fmt"
	"log/slog"
	"os"

	"github.com/spf13/cobra"

	"git.wntrmute.dev/mc/mcdsl/terminal"
	"git.wntrmute.dev/mc/metacrypt/internal/barrier"
	"git.wntrmute.dev/mc/metacrypt/internal/config"
	"git.wntrmute.dev/mc/metacrypt/internal/crypto"
	"git.wntrmute.dev/mc/metacrypt/internal/db"
	"git.wntrmute.dev/mc/metacrypt/internal/seal"
)

var initCmd = &cobra.Command{
	Use:   "init",
	Short: "Interactive first-time setup",
	Long:  "Initialize Metacrypt with a seal password. This must be run before the server can be used.",
	RunE:  runInit,
}

func init() {
	rootCmd.AddCommand(initCmd)
}

func runInit(cmd *cobra.Command, args []string) error {
	configPath := cfgFile
	if configPath == "" {
		configPath = "/srv/metacrypt/metacrypt.toml"
	}

	cfg, err := config.Load(configPath)
	if err != nil {
		return err
	}

	database, err := db.Open(cfg.Database.Path)
	if err != nil {
		return err
	}
	defer func() { _ = database.Close() }()

	if err := db.Migrate(database); err != nil {
		return err
	}

	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
	b := barrier.NewAESGCMBarrier(database)
	sealMgr := seal.NewManager(database, b, nil, logger)
	if err := sealMgr.CheckInitialized(); err != nil {
		return err
	}
	if sealMgr.State() != seal.StateUninitialized {
		return fmt.Errorf("already initialized")
	}

	pw1, err := terminal.ReadPasswordBytes("Enter seal password: ")
	if err != nil {
		return fmt.Errorf("reading password: %w", err)
	}

	pw2, err := terminal.ReadPasswordBytes("Confirm seal password: ")
	if err != nil {
		return fmt.Errorf("reading password: %w", err)
	}

	if !crypto.ConstantTimeEqual(pw1, pw2) {
		return fmt.Errorf("passwords do not match")
	}

	params := crypto.Argon2Params{
		Time:    cfg.Seal.Argon2Time,
		Memory:  cfg.Seal.Argon2Memory,
		Threads: cfg.Seal.Argon2Threads,
	}

	fmt.Println("Initializing (this may take a moment)...")
	if err := sealMgr.Initialize(context.Background(), pw1, params); err != nil {
		return err
	}

	crypto.Zeroize(pw1)
	crypto.Zeroize(pw2)

	fmt.Println("Metacrypt initialized and unsealed successfully.")
	return nil
}
