package executor

import (
	"testing"

	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/parser"
	"github.com/everything-on-mysql/cassandra-on-mysql/pkg/cql/translator"
)

func TestBuildCounterUpdatePlanIncrement(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET cnt = cnt + ? WHERE id = ?")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	columnTypes := map[string]string{
		"cnt": "counter",
		"id":  "int",
	}
	assignments, isCounter, err := collectCounterAssignments(updateStmt.Assigments, columnTypes)
	if err != nil {
		t.Fatalf("collectCounterAssignments failed: %v", err)
	}
	if !isCounter {
		t.Fatalf("expected counter update detection")
	}
	whereConditions, err := extractEqualityConditions(updateStmt.Where)
	if err != nil {
		t.Fatalf("extractEqualityConditions failed: %v", err)
	}
	dml := &dmlExecutor{Executor: &Executor{translator: translator.NewTranslator()}}
	plan, err := dml.buildCounterUpdatePlan(updateStmt.Table, assignments, whereConditions, buildBindMarkerIndex(updateStmt), columnTypes)
	if err != nil {
		t.Fatalf("buildCounterUpdatePlan failed: %v", err)
	}
	expectedSQL := "INSERT INTO `ks`.`tbl` (`cnt`, `id`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `cnt` = `cnt` + VALUES(`cnt`)"
	if plan.sql != expectedSQL {
		t.Fatalf("unexpected SQL: %s", plan.sql)
	}
	if len(plan.paramOrder) != 2 || plan.paramOrder[0] != 0 || plan.paramOrder[1] != 1 {
		t.Fatalf("unexpected param order: %#v", plan.paramOrder)
	}
}

func TestBuildCounterUpdatePlanDecrement(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET cnt = cnt - ? WHERE id = ?")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	columnTypes := map[string]string{
		"cnt": "counter",
		"id":  "int",
	}
	assignments, isCounter, err := collectCounterAssignments(updateStmt.Assigments, columnTypes)
	if err != nil {
		t.Fatalf("collectCounterAssignments failed: %v", err)
	}
	if !isCounter {
		t.Fatalf("expected counter update detection")
	}
	whereConditions, err := extractEqualityConditions(updateStmt.Where)
	if err != nil {
		t.Fatalf("extractEqualityConditions failed: %v", err)
	}
	dml := &dmlExecutor{Executor: &Executor{translator: translator.NewTranslator()}}
	plan, err := dml.buildCounterUpdatePlan(updateStmt.Table, assignments, whereConditions, buildBindMarkerIndex(updateStmt), columnTypes)
	if err != nil {
		t.Fatalf("buildCounterUpdatePlan failed: %v", err)
	}
	expectedSQL := "INSERT INTO `ks`.`tbl` (`cnt`, `id`) VALUES (-?, ?) ON DUPLICATE KEY UPDATE `cnt` = `cnt` + VALUES(`cnt`)"
	if plan.sql != expectedSQL {
		t.Fatalf("unexpected SQL: %s", plan.sql)
	}
	if len(plan.paramOrder) != 2 || plan.paramOrder[0] != 0 || plan.paramOrder[1] != 1 {
		t.Fatalf("unexpected param order: %#v", plan.paramOrder)
	}
}

func TestCollectCounterAssignmentsRejectsDirectSet(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET cnt = ? WHERE id = ?")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	columnTypes := map[string]string{
		"cnt": "counter",
		"id":  "int",
	}
	_, _, err := collectCounterAssignments(updateStmt.Assigments, columnTypes)
	if err == nil {
		t.Fatalf("expected counter assignment error")
	}
}
