package executor

import (
	"context"
	"encoding/binary"
	"errors"
	"testing"

	"go.uber.org/zap"

	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/cqlerrors"
	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/mysqlbackend"
)

func TestExecutePreparedSystemQuery(t *testing.T) {
	pool := mysqlbackend.NewPoolManager(&mysqlbackend.PoolConfig{
		Host: "localhost:3306",
	}, zap.NewNop())
	exec := NewExecutor(pool, zap.NewNop())

	ctx := context.Background()
	prepared, err := exec.Prepare(ctx, "user", "pass", "SELECT * FROM system.local")
	if err != nil {
		t.Fatalf("Prepare failed: %v", err)
	}
	if !prepared.IsSelect {
		t.Fatalf("expected IsSelect to be true")
	}

	result, err := exec.ExecutePrepared(ctx, "user", "pass", prepared.ID, nil)
	if err != nil {
		t.Fatalf("ExecutePrepared failed: %v", err)
	}
	if len(result.Rows) == 0 {
		t.Fatalf("expected rows for system.local")
	}
}

func TestDecodeParams(t *testing.T) {
	pool := mysqlbackend.NewPoolManager(&mysqlbackend.PoolConfig{
		Host: "localhost:3306",
	}, zap.NewNop())
	exec := NewExecutor(pool, zap.NewNop())

	intBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(intBytes, 42)

	params := []interface{}{intBytes}
	types := []string{"int"}
	decoded, err := exec.DecodeParams(context.Background(), "", "", params, types)
	if err != nil {
		t.Fatalf("DecodeParams failed: %v", err)
	}
	if len(decoded) != 1 {
		t.Fatalf("expected 1 decoded param, got %d", len(decoded))
	}
	if got, ok := decoded[0].(int32); !ok || got != 42 {
		t.Fatalf("expected int32(42), got %#v", decoded[0])
	}
}

func TestExecutePreparedMissingReturnsUnprepared(t *testing.T) {
	pool := mysqlbackend.NewPoolManager(&mysqlbackend.PoolConfig{
		Host: "localhost:3306",
	}, zap.NewNop())
	exec := NewExecutor(pool, zap.NewNop())

	ctx := context.Background()
	_, err := exec.ExecutePrepared(ctx, "user", "pass", "missing", nil)
	if err == nil {
		t.Fatalf("expected error for missing prepared statement")
	}

	var coder interface{ Code() int }
	if !errors.As(err, &coder) {
		t.Fatalf("expected error with Code() method, got %T", err)
	}
	if got := coder.Code(); got != cqlerrors.CodeUnprepared {
		t.Fatalf("expected unprepared code %d, got %d", cqlerrors.CodeUnprepared, got)
	}
}
