// reset-admin resets a panel user's password.
//
// Two modes:
//
//	reset-admin --email admin@panel.local --password NEWPW [--db-url postgres://...]
//	    Connects to Postgres (flag, or $PANEL_DB_URL, or the controller's
//	    default dev DSN) and writes a fresh argon2id hash for that user.
//
//	reset-admin <password>
//	    Legacy: prints the argon2id hash to stdout for a manual
//	    `UPDATE users SET password_hash = '...'`.
package main

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/jackc/pgx/v5"
	"golang.org/x/crypto/argon2"
)

// Must match controller/cmd/controller/auth.go hashPassword parameters.
const (
	argonTime    = 3
	argonMemory  = 64 * 1024
	argonThreads = 2
	argonKeyLen  = 32
	argonSaltLen = 16

	defaultDBURL = "postgres://panel:panel_dev@127.0.0.1:5432/panel?sslmode=disable"
)

func hash(password string) (string, error) {
	salt := make([]byte, argonSaltLen)
	if _, err := rand.Read(salt); err != nil {
		return "", err
	}
	h := argon2.IDKey([]byte(password), salt, argonTime, argonMemory, argonThreads, argonKeyLen)
	return fmt.Sprintf("$argon2id$v=19$m=%d,t=%d,p=%d$%s$%s",
		argonMemory, argonTime, argonThreads,
		base64.RawStdEncoding.EncodeToString(salt),
		base64.RawStdEncoding.EncodeToString(h),
	), nil
}

func main() {
	email := flag.String("email", "", "user email to reset (writes the DB; e.g. admin@panel.local)")
	password := flag.String("password", "", "new password (used with --email)")
	dbURL := flag.String("db-url", "", "Postgres connection string (default: $PANEL_DB_URL, else the controller's dev default)")
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `usage:
  reset-admin --email EMAIL --password NEWPW [--db-url postgres://...]
  reset-admin <password>          (hash-only: prints argon2id hash for manual UPDATE)`)
	}
	flag.Parse()

	// Legacy hash-only mode: one positional arg, no --email.
	if *email == "" {
		if flag.NArg() != 1 {
			flag.Usage()
			os.Exit(2)
		}
		h, err := hash(flag.Arg(0))
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		fmt.Println(h)
		return
	}

	if *password == "" {
		fmt.Fprintln(os.Stderr, "reset-admin: --password is required with --email")
		os.Exit(2)
	}
	dsn := *dbURL
	if dsn == "" {
		dsn = os.Getenv("PANEL_DB_URL")
	}
	if dsn == "" {
		dsn = defaultDBURL
	}

	h, err := hash(*password)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	defer cancel()
	conn, err := pgx.Connect(ctx, dsn)
	if err != nil {
		fmt.Fprintf(os.Stderr, "reset-admin: connect: %v\n", err)
		os.Exit(1)
	}
	defer conn.Close(ctx)

	tag, err := conn.Exec(ctx,
		`UPDATE users SET password_hash = $1, updated_at = NOW() WHERE email = $2`,
		h, *email)
	if err != nil {
		fmt.Fprintf(os.Stderr, "reset-admin: update: %v\n", err)
		os.Exit(1)
	}
	if tag.RowsAffected() == 0 {
		fmt.Fprintf(os.Stderr, "reset-admin: no user with email %q\n", *email)
		os.Exit(1)
	}
	fmt.Printf("reset-admin: password updated for %s\n", *email)
}
