package commands

import (
	"strings"
	"testing"

	"c65gm/internal/compiler"
	"c65gm/internal/preproc"
)

func TestAndCommand_WillHandle(t *testing.T) {
	cmd := &AndCommand{}

	tests := []struct {
		name string
		line string
		want bool
	}{
		{"old syntax WITH/GIVING", "AND a WITH b GIVING c", true},
		{"old syntax WITH/arrow", "AND a WITH b -> c", true},
		{"new syntax", "result = x & y", true},
		{"not AND", "ADD a TO b GIVING c", false},
		{"wrong param count", "AND a b c", false},
		{"empty", "", false},
		{"new syntax wrong op", "result = x + y", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			line := preproc.Line{Text: tt.line, Kind: preproc.Source}
			got := cmd.WillHandle(line)
			if got != tt.want {
				t.Errorf("WillHandle() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestAndCommand_OldSyntax(t *testing.T) {
	tests := []struct {
		name      string
		line      string
		setupVars func(*compiler.SymbolTable)
		wantAsm   []string
		wantErr   bool
	}{
		{
			name: "byte AND byte -> byte (variables)",
			line: "AND a WITH b GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0x0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand b",
				"\tsta result",
			},
		},
		{
			name: "byte AND byte -> word",
			line: "AND a WITH b GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0x0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand b",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "word AND word -> word",
			line: "AND x WITH y GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("x", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("y", "", compiler.KindWord, 0x0F0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda x",
				"\tand y",
				"\tsta result",
				"\tlda x+1",
				"\tand y+1",
				"\tsta result+1",
			},
		},
		{
			name: "byte AND literal -> byte",
			line: "AND a WITH $F0 GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand #$f0",
				"\tsta result",
			},
		},
		{
			name: "literal AND byte -> byte",
			line: "AND 255 WITH b GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("b", "", compiler.KindByte, 0x0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda b",
				"\tsta result",
			},
		},
		{
			name: "constant folding: 255 AND 15 -> byte",
			line: "AND 255 WITH 15 GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$0f",
				"\tsta result",
			},
		},
		{
			name: "constant folding: $FFFF AND $0F0F -> word",
			line: "AND $FFFF WITH $0F0F GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$0f",
				"\tsta result",
				"\tlda #$0f",
				"\tsta result+1",
			},
		},
		{
			name: "arrow syntax",
			line: "AND a WITH b -> result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand b",
				"\tsta result",
			},
		},
		{
			name: "word AND byte -> byte",
			line: "AND wval WITH bval GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("bval", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand bval",
				"\tsta result",
			},
		},
		{
			name: "word AND byte -> word",
			line: "AND wval WITH bval GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("bval", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand bval",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "error: unknown destination variable",
			line: "AND a WITH b GIVING unknown",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantErr: true,
		},
		{
			name: "error: wrong separator",
			line: "AND a TO b GIVING result",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantErr: true,
		},
		{
			name: "error: cannot assign to constant",
			line: "AND a WITH b GIVING MAXVAL",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddConst("MAXVAL", "", compiler.KindByte, 255, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := compiler.NewCompilerContext(&preproc.Pragma{})
			tt.setupVars(ctx.SymbolTable)

			cmd := &AndCommand{}
			line := preproc.Line{Text: tt.line, Kind: preproc.Source}

			err := cmd.Interpret(line, ctx)
			if tt.wantErr {
				if err == nil {
					t.Error("expected error, got nil")
				}
				return
			}
			if err != nil {
				t.Fatalf("Interpret() error = %v", err)
			}

			asm, err := cmd.Generate(ctx)
			if err != nil {
				t.Fatalf("Generate() error = %v", err)
			}

			if !equalAsm(asm, tt.wantAsm) {
				t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
					strings.Join(asm, "\n"),
					strings.Join(tt.wantAsm, "\n"))
			}
		})
	}
}

func TestAndCommand_NewSyntax(t *testing.T) {
	tests := []struct {
		name      string
		line      string
		setupVars func(*compiler.SymbolTable)
		wantAsm   []string
		wantErr   bool
	}{
		{
			name: "byte & byte -> byte",
			line: "result = a & b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0x0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand b",
				"\tsta result",
			},
		},
		{
			name: "byte & byte -> word",
			line: "result = a & b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0x0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand b",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "word & word -> word",
			line: "result = x & y",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("x", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("y", "", compiler.KindWord, 0x0F0F, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda x",
				"\tand y",
				"\tsta result",
				"\tlda x+1",
				"\tand y+1",
				"\tsta result+1",
			},
		},
		{
			name: "variable & literal",
			line: "result = a & $F0",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand #$f0",
				"\tsta result",
			},
		},
		{
			name: "byte & $FF -> byte (optimization: skip and #$ff)",
			line: "result = a & $FF",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tsta result",
			},
		},
		{
			name: "byte & $FF -> word (optimization: skip and #$ff)",
			line: "result = a & $FF",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "byte & 0 -> byte (optimization: lda #0)",
			line: "result = a & 0",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
			},
		},
		{
			name: "0 & byte -> byte (optimization: lda #0)",
			line: "result = 0 & a",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
			},
		},
		{
			name: "byte & 0 -> word (optimization: lda #0)",
			line: "result = a & 0",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
				"\tsta result+1",
			},
		},
		{
			name: "byte & $100 -> byte (optimization: lda #0, low byte of $100 is 0)",
			line: "result = a & $100",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
			},
		},
		{
			name: "byte & $100 -> word (optimization: lda #0)",
			line: "result = a & $100",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
				"\tlda #0",
				"\tand #$01",
				"\tsta result+1",
			},
		},
		{
			name: "constant folding",
			line: "result = 255 & 15",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$0f",
				"\tsta result",
			},
		},
		{
			name: "constant folding word",
			line: "result = $FFFF & $1234",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$34",
				"\tsta result",
				"\tlda #$12",
				"\tsta result+1",
			},
		},
		{
			name: "using constant in expression",
			line: "result = a & MASK",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddConst("MASK", "", compiler.KindByte, 0xF0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tand #$f0",
				"\tsta result",
			},
		},
		{
			name: "byte & byte -> byte (same variable: a & a = a)",
			line: "result = a & a",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tsta result",
			},
		},
		{
			name: "word & word -> word (same variable: x & x = x)",
			line: "result = x & x",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("x", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda x",
				"\tsta result",
				"\tlda x+1",
				"\tsta result+1",
			},
		},
		{
			name: "$FF & byte -> word (optimization: lda param2)",
			line: "result = $FF & a",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda a",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "byte & word -> byte (swap case)",
			line: "result = bval & wval",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("bval", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand bval",
				"\tsta result",
			},
		},
		{
			name: "byte & word -> word (swap case)",
			line: "result = bval & wval",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("bval", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand bval",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "word_const & byte -> byte",
			line: "result = 300 & b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("b", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$2c",
				"\tand b",
				"\tsta result",
			},
		},
		{
			name: "word_const & byte -> word",
			line: "result = 300 & b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("b", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #$2c",
				"\tand b",
				"\tsta result",
				"\tlda #0",
				"\tsta result+1",
			},
		},
		{
			name: "byte & word_const -> byte",
			line: "result = b & 300",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("b", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda b",
				"\tand #$2c",
				"\tsta result",
			},
		},
		{
			name: "byte & word_const -> word",
			line: "result = b & 300",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("b", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda b",
				"\tand #$2c",
				"\tsta result",
				"\tlda #0",
				"\tand #$01",
				"\tsta result+1",
			},
		},
		{
			name: "0 & byte -> word (optimization: lda #0, skip high byte)",
			line: "result = 0 & a",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0xAB, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda #0",
				"\tsta result",
				"\tsta result+1",
			},
		},
		{
			name: "self-assignment: word &= byte",
			line: "wval = wval & bval",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("bval", "", compiler.KindByte, 0xFF, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand bval",
				"\tsta wval",
				"\tlda #0",
				"\tsta wval+1",
			},
		},
		{
			name: "self-assignment: word &= byte_const",
			line: "wval = wval & 42",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand #$2a",
				"\tsta wval",
				"\tlda #0",
				"\tsta wval+1",
			},
		},
		{
			name: "self-assignment: word &= word_const",
			line: "wval = wval & 300",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand #$2c",
				"\tsta wval",
				"\tlda wval+1",
				"\tand #$01",
				"\tsta wval+1",
			},
		},
		{
			name: "self-assignment: word &= word",
			line: "wval = wval & wval2",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("wval", "", compiler.KindWord, 0x1234, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("wval2", "", compiler.KindWord, 0x5678, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantAsm: []string{
				"\tlda wval",
				"\tand wval2",
				"\tsta wval",
				"\tlda wval+1",
				"\tand wval2+1",
				"\tsta wval+1",
			},
		},
		{
			name: "error: unknown destination",
			line: "unknown = a & b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantErr: true,
		},
		{
			name: "error: wrong operator",
			line: "result = a + b",
			setupVars: func(st *compiler.SymbolTable) {
				st.AddVar("a", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("b", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
				st.AddVar("result", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := compiler.NewCompilerContext(&preproc.Pragma{})
			tt.setupVars(ctx.SymbolTable)

			cmd := &AndCommand{}
			line := preproc.Line{Text: tt.line, Kind: preproc.Source}

			err := cmd.Interpret(line, ctx)
			if tt.wantErr {
				if err == nil {
					t.Error("expected error, got nil")
				}
				return
			}
			if err != nil {
				t.Fatalf("Interpret() error = %v", err)
			}

			asm, err := cmd.Generate(ctx)
			if err != nil {
				t.Fatalf("Generate() error = %v", err)
			}

			if !equalAsm(asm, tt.wantAsm) {
				t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
					strings.Join(asm, "\n"),
					strings.Join(tt.wantAsm, "\n"))
			}
		})
	}
}

/*
// equalAsm compares two assembly slices for equality
func equalAsm(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}


*/
