package duckdb

import (
	"strings"
	"testing"

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

func TestGenerateBinaryPlanJSON(t *testing.T) {
	// Test case 1: Valid binary plan
	input := "YPBMClwKDEltcG9ydEludG9fMjgBQAFSA04vQVotdGltZToxLjE3bXMsIG9wZW46MTkybnMsIGNsb3NlOjY5N25zLCBsb29wczoxcP////8FAzQBeP///////////wEYAQ=="

	result, err := GenerateBinaryPlanJSON(input)
	if err != nil {
		t.Fatalf("GenerateBinaryPlanJSON failed: %v", err)
	}

	t.Logf("Generated Binary Plan JSON result: %s", result)

	// Verify the result is not empty
	if result == "" {
		t.Error("Expected non-empty result")
	}

	// Test case 2: Empty input
	emptyResult, err := GenerateBinaryPlanJSON("")
	if err != nil {
		t.Fatalf("GenerateBinaryPlanJSON with empty input failed: %v", err)
	}

	if emptyResult != "" {
		t.Errorf("Expected empty result for empty input, got: %s", emptyResult)
	}

	// Test case 3: Invalid base64 input
	_, err = GenerateBinaryPlanJSON("invalid_base64")
	if err == nil {
		t.Error("Expected error for invalid base64 input, but got none")
	}

	t.Logf("Invalid base64 test error (expected): %v", err)
}

func TestNormalizeBinaryPlanPayload(t *testing.T) {
	raw := "YPBMClwKDEltcG9ydEludG9fMjgBQAFSA04vQVotdGltZToxLjE3bXMsIG9wZW46MTkybnMsIGNsb3NlOjY5N25zLCBsb29wczoxcP////8FAzQBeP///////////wEYAQ=="
	assert.Equal(t, raw, NormalizeBinaryPlanPayload(raw))
	assert.Equal(t, raw, NormalizeBinaryPlanPayload("tidb_decode_binary_plan('"+raw+"')"))
	assert.Equal(t, "", NormalizeBinaryPlanPayload("   "))
}

func TestEnrichBinaryPlanFields(t *testing.T) {
	raw := "YPBMClwKDEltcG9ydEludG9fMjgBQAFSA04vQVotdGltZToxLjE3bXMsIG9wZW46MTkybnMsIGNsb3NlOjY5N25zLCBsb29wczoxcP////8FAzQBeP///////////wEYAQ=="
	row := map[string]interface{}{}
	EnrichBinaryPlanFields(row, "tidb_decode_binary_plan('"+raw+"')")

	require.NotNil(t, row["binary_plan"])
	require.NotNil(t, row["binary_plan_text"])
	jsonPlan, ok := row["binary_plan"].(string)
	require.True(t, ok)
	assert.NotEmpty(t, jsonPlan)
	textPlan, ok := row["binary_plan_text"].(string)
	require.True(t, ok)
	assert.NotEmpty(t, textPlan)
	// Text plan should look like a tabular explain output, not JSON.
	assert.False(t, strings.HasPrefix(strings.TrimSpace(textPlan), "{"))

	emptyRow := map[string]interface{}{}
	EnrichBinaryPlanFields(emptyRow, "")
	assert.Nil(t, emptyRow["binary_plan"])
	assert.Nil(t, emptyRow["binary_plan_text"])
}

func TestDecodePlanField(t *testing.T) {
	encoded := "ffBhMAkzXzMJMAkxCXNsZWVwKDEpLT5Db2x1bW4jMQkxCXRpbWU6MXMsIGxvb3BzOjIsIENvbmN1cnJlbmN5Ok9GRgkwIEJ5dGVzCU4vQQoxCTI1XzQJMAkxCXJvd3M6MQkxCXQBQgwyOThuGUUgCU4vQQlOL0EK"

	decoded := DecodePlanField(encoded)
	require.NotEmpty(t, decoded)
	assert.Contains(t, decoded, "operator info")
	assert.Contains(t, decoded, "Projection_3")

	wrapped := DecodePlanField("tidb_decode_plan('" + encoded + "')")
	assert.Equal(t, decoded, wrapped)

	// Already-decoded v1-style text is returned as-is.
	plain := "\tid\ttask\testRows\toperator info\n\tTableScan_1\troot\t1\ttable:t"
	assert.Equal(t, plain, DecodePlanField(plain))

	// Plaintext that is not compressed encoding is returned as-is.
	assert.Equal(t, "TableScan -> Limit", DecodePlanField("TableScan -> Limit"))
	assert.Equal(t, "", DecodePlanField("   "))
}
