package cmd

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"syscall"

	"github.com/artalkjs/artalk/v2/internal/entity"
	"github.com/artalkjs/artalk/v2/internal/i18n"
	"github.com/artalkjs/artalk/v2/internal/log"
	"github.com/artalkjs/artalk/v2/internal/utils"
	"github.com/spf13/cobra"
	"golang.org/x/term"
)

func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
	adminCmd := &cobra.Command{
		Use:   "admin",
		Short: "Create or edit an administrator account",
		Args:  cobra.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("--------------------------------")
			fmt.Println(" " + i18n.T("Create admin account"))
			fmt.Println("--------------------------------")

			// get from flags
			username, _ := cmd.Flags().GetString("name")
			email, _ := cmd.Flags().GetString("email")
			password, _ := cmd.Flags().GetString("password")

			if username == "" || email == "" || password == "" {
				var err error
				username, email, password, err = credentials()
				if err != nil {
					log.Fatal(err)
				}
			}

			findUser := app.Dao().FindUser(username, email)
			if !findUser.IsEmpty() {
				findUser.SetPasswordEncrypt(password)
				findUser.IsAdmin = true
				if err := app.Dao().UpdateUser(&findUser); err != nil {
					log.Fatal(err)
				}

				log.Info(i18n.T("{{name}} already exists", map[string]interface{}{"name": i18n.T("Account")}) +
					", " + i18n.T("Password updated"))
				return
			}

			user := entity.User{
				Name:       username,
				Email:      email,
				IsAdmin:    true,
				BadgeName:  i18n.T("Admin"),
				BadgeColor: "#0083FF",
			}
			user.SetPasswordEncrypt(password)

			if err := app.Dao().CreateUser(&user); err != nil {
				log.Fatal(err)
			}

			fmt.Println("--------------------------------")
			fmt.Println("  Name: " + username)
			fmt.Println("  Mail: " + email)
			fmt.Println("--------------------------------")
		},
	}

	flag(adminCmd, "name", "", i18n.T("Username"))
	flag(adminCmd, "email", "", i18n.T("Email"))
	flag(adminCmd, "password", "", i18n.T("Password"))

	return adminCmd
}

func credentials() (string, string, string, error) {
	reader := bufio.NewReader(os.Stdin)

	fmt.Print(i18n.T("Enter {{name}}", map[string]interface{}{"name": i18n.T("Username")}) + ": ")
	username, err := reader.ReadString('\n')
	if err != nil {
		return "", "", "", err
	}

	fmt.Print(i18n.T("Enter {{name}}", map[string]interface{}{"name": i18n.T("Email")}) + ": ")
	email, err := reader.ReadString('\n')
	if err != nil {
		return "", "", "", err
	}
	if !utils.ValidateEmail(strings.TrimSpace(email)) {
		return "", "", "", fmt.Errorf("invalid email format")
	}

	fmt.Print(i18n.T("Enter {{name}}", map[string]interface{}{"name": i18n.T("Password")}) + ": ")
	bytePassword, err := term.ReadPassword(int(syscall.Stdin))
	if err != nil {
		return "", "", "", err
	}

	fmt.Println()
	fmt.Print(i18n.T("Retype {{name}}", map[string]interface{}{"name": i18n.T("Password")}) + ": ")
	byteRePassword, err := term.ReadPassword(int(syscall.Stdin))
	if err != nil {
		return "", "", "", err
	}

	fmt.Println()

	password := strings.TrimSpace(string(bytePassword))
	rePassword := strings.TrimSpace(string(byteRePassword))

	if rePassword != password {
		return "", "", "", fmt.Errorf("inconsistent password input")
	}

	return strings.TrimSpace(username), strings.TrimSpace(email), password, nil
}
