package cli

import (
	"fmt"
	"testing"
	"time"

	"os"

	"github.com/stretchr/testify/require"
)

// Counter
type Counter int

func (d *Counter) Set(v string) error {
	*d++
	return nil
}

func (d *Counter) String() string {
	return fmt.Sprintf("%d", *d)
}

func (d *Counter) IsBoolFlag() bool {
	return true
}

// Duration
type Duration time.Duration

func (d *Duration) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = Duration(parsed)
	return nil
}

func (d *Duration) String() string {
	duration := time.Duration(*d)
	return duration.String()
}

type Percent []float64

func parsePercent(v string) (float64, error) {
	var d int
	_, err := fmt.Sscanf(v, "%d%%", &d)
	if err != nil {
		return 0, err
	}
	return float64(d) / 100, nil
}

func (p *Percent) Set(v string) error {
	f, err := parsePercent(v)
	if err != nil {
		return err
	}
	*p = append(*p, f)
	return nil
}

func (p *Percent) Clear() {
	*p = nil
}

func (p *Percent) String() string {
	res := "["
	for idx, p := range *p {
		if idx > 0 {
			res += ", "
		}
		res += fmt.Sprintf("%.0f%%", p*100)
	}
	return res + "]"
}

func TestVar(t *testing.T) {
	value := Counter(0)
	duration := Duration(0)
	percents := Percent{}

	app := App("var", "")
	app.Spec = "-v... DURATION PERCENT..."

	app.VarOpt("v", &value, "")
	app.VarArg("DURATION", &duration, "")
	app.VarArg("PERCENT", &percents, "")

	ex := false
	app.Action = func() {
		ex = true
	}
	require.NoError(t,
		app.Run([]string{"cp", "-vvv", "1h", "10%", "5%"}))

	require.Equal(t, Counter(3), value)
	require.Equal(t, Duration(1*time.Hour), duration)
	require.Equal(t, Percent([]float64{0.1, 0.05}), percents)

	require.True(t, ex, "Exec wasn't called")
}

func TestVarFromEnv(t *testing.T) {
	os.Setenv("MOWCLI_DURATION", "1h2m3s")
	os.Setenv("MOWCLI_ARG_PERCENTS", "25%, 1%")
	os.Setenv("MOWCLI_OPT_PERCENTS", "90%, 42%")

	duration := Duration(0)
	argPercents := Percent{}
	optPercents := Percent{}

	app := App("var", "")
	app.Spec = "-p... DURATION PERCENT..."

	app.Var(VarArg{
		Name:   "DURATION",
		Value:  &duration,
		EnvVar: "MOWCLI_DURATION",
	})
	app.Var(VarArg{
		Name:   "PERCENT",
		Value:  &argPercents,
		EnvVar: "MOWCLI_ARG_PERCENTS",
	})
	app.Var(VarOpt{
		Name:   "p",
		Value:  &optPercents,
		EnvVar: "MOWCLI_OPT_PERCENTS",
	})

	require.Equal(t, Duration(1*time.Hour+2*time.Minute+3*time.Second), duration)

	require.Equal(t, Percent([]float64{0.25, 0.01}), argPercents)
	require.Equal(t, Percent([]float64{0.9, 0.42}), optPercents)
}

func TestVarOverrideEnv(t *testing.T) {
	os.Setenv("MOWCLI_PERCENTS", "25%, 1%")

	percents := Percent{}

	app := App("var", "")
	app.Spec = "PERCENT..."
	app.Var(VarArg{
		Name:   "PERCENT",
		Value:  &percents,
		EnvVar: "MOWCLI_PERCENTS",
	})

	ex := false
	app.Action = func() {
		ex = true
		require.Equal(t, Percent([]float64{0, 0.99}), percents)
	}

	require.NoError(t,
		app.Run([]string{"var", "0%", "99%"}))

	require.True(t, ex, "Action should have been called")
}
