// Copyright 2025 eat-pray-ai & OpenWaygate
// SPDX-License-Identifier: Apache-2.0

package utils

import (
	"bytes"
	"fmt"
	"reflect"
	"testing"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func TestStrToBoolPtr(t *testing.T) {
	type args struct {
		b *string
	}
	tests := []struct {
		name string
		args args
		want *bool
	}{
		{
			name: "true",
			args: args{b: new("true")},
			want: func() *bool {
				b := true
				return &b
			}(),
		},
		{
			name: "false",
			args: args{b: new("false")},
			want: func() *bool {
				b := false
				return &b
			}(),
		},
		{
			name: "empty",
			args: args{b: new("")},
			want: nil,
		},
		{
			name: "null",
			args: args{b: new("null")},
			want: nil,
		},
		{
			name: "NULL",
			args: args{b: new("NULL")},
			want: nil,
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				if got := StrToBoolPtr(tt.args.b); !reflect.DeepEqual(got, tt.want) {
					t.Errorf("BoolPtr() = %v, want %v", got, tt.want)
				}
			},
		)
	}
}

func TestGetFileName(t *testing.T) {
	type args struct {
		file string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "with extension",
			args: args{file: "example.txt"},
			want: "example",
		},
		{
			name: "without extension",
			args: args{file: "example"},
			want: "example",
		},
		{
			name: "with path",
			args: args{file: "/foo/bar/example.txt"},
			want: "example",
		},
		{
			name: "double extension",
			args: args{file: "archive.tar.gz"},
			want: "archive.tar",
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				if got := GetFileName(tt.args.file); got != tt.want {
					t.Errorf("GetFileName() = %v, want %v", got, tt.want)
				}
			},
		)
	}
}

func TestIsJson(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "valid json",
			args: args{s: `{"key": "value"}`},
			want: true,
		},
		{
			name: "invalid json",
			args: args{s: `{"key": "value"`},
			want: false,
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				if got := IsJson(tt.args.s); got != tt.want {
					t.Errorf("IsJson() = %v, want %v", got, tt.want)
				}
			},
		)
	}
}

func TestPrintJSON(t *testing.T) {
	tests := []struct {
		name       string
		data       any
		wantWriter string
	}{
		{
			name:       "simple json",
			data:       map[string]string{"key": "value"},
			wantWriter: "{\n  \"key\": \"value\"\n}\n",
		},
		{
			name:       "nil data",
			data:       nil,
			wantWriter: "null\n",
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				writer := &bytes.Buffer{}
				PrintJSON(tt.data, writer)
				if gotWriter := writer.String(); gotWriter != tt.wantWriter {
					t.Errorf("PrintJSON() = %v, want %v", gotWriter, tt.wantWriter)
				}
			},
		)
	}
}

func TestPrintYAML(t *testing.T) {
	tests := []struct {
		name       string
		data       any
		wantWriter string
	}{
		{
			name:       "simple yaml",
			data:       map[string]string{"key": "value"},
			wantWriter: "key: value\n\n",
		},
		{
			name:       "nil data",
			data:       nil,
			wantWriter: "null\n\n",
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				writer := &bytes.Buffer{}
				PrintYAML(tt.data, writer)
				if gotWriter := writer.String(); gotWriter != tt.wantWriter {
					t.Errorf("PrintYAML() = %v, want %v", gotWriter, tt.wantWriter)
				}
			},
		)
	}
}

func TestResetBool(t *testing.T) {
	type args struct {
		m       map[string]**bool
		flagSet *pflag.FlagSet
	}
	b := new(true)
	cmd := &cobra.Command{}
	cmd.Flags().BoolVar(b, "flag", false, "")
	tests := []struct {
		name string
		args args
	}{
		{
			name: "reset bool flags",
			args: args{
				m: map[string]**bool{
					"flag": &b,
				},
				flagSet: cmd.Flags(),
			},
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				ResetBool(tt.args.m, tt.args.flagSet)
				if b != nil {
					t.Errorf("ResetBool() = %v, want nil", *b)
				}
			},
		)
	}
}

func TestExtractHl(t *testing.T) {
	type args struct {
		uri string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "valid language uri with hl",
			args: args{uri: "i18n://language/zh-CN"},
			want: "zh-CN",
		},
		{
			name: "valid region uri with hl",
			args: args{uri: "i18n://region/zh-CN"},
			want: "zh-CN",
		},
		{
			name: "valid language uri without hl",
			args: args{uri: "i18n://language/"},
			want: "",
		},
		{
			name: "valid region uri without hl",
			args: args{uri: "i18n://region/"},
			want: "",
		},
		{
			name: "invalid uri",
			args: args{uri: "i18n://invalid/zh-CN"},
			want: "",
		},
		{
			name: "empty uri",
			args: args{uri: ""},
			want: "",
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				if got := ExtractHl(tt.args.uri); got != tt.want {
					t.Errorf("ExtractHl() = %v, want %v", got, tt.want)
				}
			},
		)
	}
}

func TestBoolToStrPtr(t *testing.T) {
	bTrue := true
	bFalse := false
	type args struct {
		b *bool
	}
	tests := []struct {
		name string
		args args
		want *string
	}{
		{
			name: "true",
			args: args{b: &bTrue},
			want: new("true"),
		},
		{
			name: "false",
			args: args{b: &bFalse},
			want: new("false"),
		},
		{
			name: "nil",
			args: args{b: nil},
			want: new(""),
		},
	}
	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				if got := BoolToStrPtr(tt.args.b); !reflect.DeepEqual(got, tt.want) {
					t.Errorf("BoolToStrPtr() = %v, want %v", got, tt.want)
				}
			},
		)
	}
}

func TestRandomStage(t *testing.T) {
	s1 := RandomStage()
	s2 := RandomStage()
	if s1 == "" {
		t.Error("RandomStage() returned empty string")
	}
	if s1 == s2 {
		t.Error("RandomStage() returned same value twice")
	}
}

func TestHandleCmdError_DryRun(t *testing.T) {
	c := &cobra.Command{Use: "test"}
	var stderr bytes.Buffer
	c.SetErr(&stderr)
	HandleCmdError(ErrDryRun, c)
	if stderr.Len() != 0 {
		t.Errorf("expected no error output for ErrDryRun, got %q", stderr.String())
	}
}

func TestHandleCmdError(t *testing.T) {
	tests := []struct {
		name    string
		input   error
		wantOut string
		wantErr string
	}{
		{
			name:    "with error",
			input:   fmt.Errorf("some error"),
			wantOut: "help called",
			wantErr: "Error: some error\n",
		},
		{
			name:    "without error",
			input:   nil,
			wantOut: "",
			wantErr: "",
		},
	}

	for _, tt := range tests {
		t.Run(
			tt.name, func(t *testing.T) {
				cmd := &cobra.Command{Use: "test"}
				var outBuf, errBuf bytes.Buffer
				cmd.SetOut(&outBuf)
				cmd.SetErr(&errBuf)
				cmd.SetHelpFunc(
					func(c *cobra.Command, args []string) {
						_, _ = fmt.Fprint(c.OutOrStdout(), "help called")
					},
				)

				HandleCmdError(tt.input, cmd)

				if gotOut := outBuf.String(); gotOut != tt.wantOut {
					t.Fatalf(
						"unexpected stdout output, got %q, want %q", gotOut, tt.wantOut,
					)
				}

				if gotErr := errBuf.String(); gotErr != tt.wantErr {
					t.Fatalf(
						"unexpected stderr output, got %q, want %q", gotErr, tt.wantErr,
					)
				}
			},
		)
	}
}
