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 TestValidateArithmeticAssignmentNumeric(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET unread = unread + 1 WHERE id = 1")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	assign := updateStmt.Assigments[0]
	if err := validateArithmeticAssignment(assign.Column, "int", assign.Value); err != nil {
		t.Fatalf("expected arithmetic assignment to be valid: %v", err)
	}
}

func TestValidateArithmeticAssignmentNonNumeric(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET name = name + 1 WHERE id = 1")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	assign := updateStmt.Assigments[0]
	if err := validateArithmeticAssignment(assign.Column, "text", assign.Value); err == nil {
		t.Fatalf("expected non-numeric arithmetic assignment to fail")
	}
}

func TestValidateArithmeticAssignmentComplex(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET unread = other + 1 WHERE id = 1")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	assign := updateStmt.Assigments[0]
	if err := validateArithmeticAssignment(assign.Column, "int", assign.Value); err == nil {
		t.Fatalf("expected complex arithmetic assignment to fail")
	}
}

func TestArithmeticAssignmentDelta(t *testing.T) {
	cases := []struct {
		name     string
		cql      string
		expected string
	}{
		{
			name:     "column plus literal",
			cql:      "UPDATE ks.tbl SET unread = unread + 1 WHERE id = 1",
			expected: "1",
		},
		{
			name:     "literal plus column",
			cql:      "UPDATE ks.tbl SET unread = 2 + unread WHERE id = 1",
			expected: "2",
		},
		{
			name:     "column minus bind marker",
			cql:      "UPDATE ks.tbl SET unread = unread - ? WHERE id = 1",
			expected: "-?",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			stmt := mustParseStatement(t, tc.cql)
			updateStmt, ok := stmt.(*parser.UpdateStatement)
			if !ok {
				t.Fatalf("expected update statement, got %T", stmt)
			}
			delta, err := arithmeticAssignmentDelta(updateStmt.Assigments[0])
			if err != nil {
				t.Fatalf("arithmeticAssignmentDelta failed: %v", err)
			}
			got := translator.NewTranslator().TranslateExpression(delta)
			if got != tc.expected {
				t.Fatalf("unexpected delta expression: got=%s want=%s", got, tc.expected)
			}
		})
	}
}

func TestArithmeticAssignmentDeltaInvalid(t *testing.T) {
	stmt := mustParseStatement(t, "UPDATE ks.tbl SET unread = other + 1 WHERE id = 1")
	updateStmt, ok := stmt.(*parser.UpdateStatement)
	if !ok {
		t.Fatalf("expected update statement, got %T", stmt)
	}
	if _, err := arithmeticAssignmentDelta(updateStmt.Assigments[0]); err == nil {
		t.Fatalf("expected invalid arithmetic delta error")
	}
}
