package debug

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

type Inst struct {
	PC       string `json:"pc"`
	Mnemonic string `json:"mnemonic"`
}

var mnemonics [256][4]string = [256][4]string{
	/* 0x0x */ {"NOP", "*", "*", "1"}, {"LD", "BC", "d16", "3"}, {"LD", "(BC)", "A", "2"}, {"INC", "BC", "*", "2"}, {"INC", "B", "*", "1"}, {"DEC", "B", "*", "1"}, {"LD", "B", "d8", "2"}, {"RLCA", "*", "*", "1"}, {"LD", "(a16)", "SP", "5"}, {"ADD", "HL", "BC", "2"}, {"LD", "A", "(BC)", "2"}, {"DEC", "BC", "*", "2"}, {"INC", "C", "*", "1"}, {"DEC", "C", "*", "1"}, {"LD", "C", "d8", "2"}, {"RRCA", "*", "*", "1"},
	/* 0x1x */ {"STOP", "0", "*", "1"}, {"LD", "DE", "d16", "3"}, {"LD", "(DE)", "A", "2"}, {"INC", "DE", "*", "2"}, {"INC", "D", "*", "1"}, {"DEC", "D", "*", "1"}, {"LD", "D", "d8", "2"}, {"RLA", "*", "*", "1"}, {"JR", "r8", "*", "3"}, {"ADD", "HL", "DE", "2"}, {"LD", "A", "(DE)", "2"}, {"DEC", "DE", "*", "2"}, {"INC", "E", "*", "1"}, {"DEC", "E", "*", "1"}, {"LD", "E", "d8", "2"}, {"RRA", "*", "*", "1"},
	/* 0x2x */ {"JR", "NZ", "r8", "1.5"}, {"LD", "HL", "d16", "3"}, {"LD", "(HL+)", "A", "2"}, {"INC", "HL", "*", "2"}, {"INC", "H", "*", "1"}, {"DEC", "H", "*", "1"}, {"LD", "H", "d8", "2"}, {"DAA", "*", "*", "1"}, {"JR", "Z", "r8", "1.5"}, {"ADD", "HL", "HL", "2"}, {"LD", "A", "(HL+)", "2"}, {"DEC", "HL", "*", "2"}, {"INC", "L", "*", "1"}, {"DEC", "L", "*", "1"}, {"LD", "L", "d8", "2"}, {"CPL", "*", "*", "1"},
	/* 0x3x */ {"JR", "NC", "r8", "1.5"}, {"LD", "SP", "d16", "3"}, {"LD", "(HL-)", "A", "2"}, {"INC", "SP", "*", "2"}, {"INC", "(HL)", "*", "3"}, {"DEC", "(HL)", "*", "3"}, {"LD", "(HL)", "d8", "3"}, {"SCF", "*", "*", "1"}, {"JR", "C", "r8", "1.5"}, {"ADD", "HL", "SP", "2"}, {"LD", "A", "(HL-)", "2"}, {"DEC", "SP", "*", "2"}, {"INC", "A", "*", "1"}, {"DEC", "A", "*", "1"}, {"LD", "A", "d8", "2"}, {"CCF", "*", "*", "1"},
	/* 0x4x */ {"LD", "B", "B", "1"}, {"LD", "B", "C", "1"}, {"LD", "B", "D", "1"}, {"LD", "B", "E", "1"}, {"LD", "B", "H", "1"}, {"LD", "B", "L", "1"}, {"LD", "B", "(HL)", "2"}, {"LD", "B", "A", "1"}, {"LD", "C", "B", "1"}, {"LD", "C", "C", "1"}, {"LD", "C", "D", "1"}, {"LD", "C", "E", "1"}, {"LD", "C", "H", "1"}, {"LD", "C", "L", "1"}, {"LD", "C", "(HL)", "2"}, {"LD", "C", "A", "1"},
	/* 0x5x */ {"LD", "D", "B", "1"}, {"LD", "D", "C", "1"}, {"LD", "D", "D", "1"}, {"LD", "D", "E", "1"}, {"LD", "D", "H", "1"}, {"LD", "D", "L", "1"}, {"LD", "D", "(HL)", "2"}, {"LD", "D", "A", "1"}, {"LD", "E", "B", "1"}, {"LD", "E", "C", "1"}, {"LD", "E", "D", "1"}, {"LD", "E", "E", "1"}, {"LD", "E", "H", "1"}, {"LD", "E", "L", "1"}, {"LD", "E", "(HL)", "2"}, {"LD", "E", "A", "1"},
	/* 0x6x */ {"LD", "H", "B", "1"}, {"LD", "H", "C", "1"}, {"LD", "H", "D", "1"}, {"LD", "H", "E", "1"}, {"LD", "H", "H", "1"}, {"LD", "H", "L", "1"}, {"LD", "H", "(HL)", "2"}, {"LD", "H", "A", "1"}, {"LD", "L", "B", "1"}, {"LD", "L", "C", "1"}, {"LD", "L", "D", "1"}, {"LD", "L", "E", "1"}, {"LD", "L", "H", "1"}, {"LD", "L", "L", "1"}, {"LD", "L", "(HL)", "2"}, {"LD", "L", "A", "1"},
	/* 0x7x */ {"LD", "(HL)", "B", "2"}, {"LD", "(HL)", "C", "2"}, {"LD", "(HL)", "D", "2"}, {"LD", "(HL)", "E", "2"}, {"LD", "(HL)", "H", "2"}, {"LD", "(HL)", "L", "2"}, {"HALT", "*", "*", "1"}, {"LD", "(HL)", "A", "2"}, {"LD", "A", "B", "1"}, {"LD", "A", "C", "1"}, {"LD", "A", "D", "1"}, {"LD", "A", "E", "1"}, {"LD", "A", "H", "1"}, {"LD", "A", "L", "1"}, {"LD", "A", "(HL)", "2"}, {"LD", "A", "A", "1"},
	/* 0x8x */ {"ADD", "A", "B", "1"}, {"ADD", "A", "C", "1"}, {"ADD", "A", "D", "1"}, {"ADD", "A", "E", "1"}, {"ADD", "A", "H", "1"}, {"ADD", "A", "L", "1"}, {"ADD", "A", "(HL)", "2"}, {"ADD", "A", "A", "1"}, {"ADC", "A", "B", "1"}, {"ADC", "A", "C", "1"}, {"ADC", "A", "D", "1"}, {"ADC", "A", "E", "1"}, {"ADC", "A", "H", "1"}, {"ADC", "A", "L", "1"}, {"ADC", "A", "(HL)", "2"}, {"ADC", "A", "A", "1"},
	/* 0x9x */ {"SUB", "B", "*", "1"}, {"SUB", "C", "*", "1"}, {"SUB", "D", "*", "1"}, {"SUB", "E", "*", "1"}, {"SUB", "H", "*", "1"}, {"SUB", "L", "*", "1"}, {"SUB", "(HL)", "*", "2"}, {"SUB", "A", "*", "1"}, {"SBC", "A", "B", "1"}, {"SBC", "A", "C", "1"}, {"SBC", "A", "D", "1"}, {"SBC", "A", "E", "1"}, {"SBC", "A", "H", "1"}, {"SBC", "A", "L", "1"}, {"SBC", "A", "(HL)", "2"}, {"SBC", "A", "A", "1"},
	/* 0xax */ {"AND", "B", "*", "1"}, {"AND", "C", "*", "1"}, {"AND", "D", "*", "1"}, {"AND", "E", "*", "1"}, {"AND", "H", "*", "1"}, {"AND", "L", "*", "1"}, {"AND", "(HL)", "*", "2"}, {"AND", "A", "*", "1"}, {"XOR", "B", "*", "1"}, {"XOR", "C", "*", "1"}, {"XOR", "D", "*", "1"}, {"XOR", "E", "*", "1"}, {"XOR", "H", "*", "1"}, {"XOR", "L", "*", "1"}, {"XOR", "(HL)", "*", "2"}, {"XOR", "A", "*", "1"},
	/* 0xbx */ {"OR", "B", "*", "1"}, {"OR", "C", "*", "1"}, {"OR", "D", "*", "1"}, {"OR", "E", "*", "1"}, {"OR", "H", "*", "1"}, {"OR", "L", "*", "1"}, {"OR", "(HL)", "*", "2"}, {"OR", "A", "*", "1"}, {"CP", "B", "*", "1"}, {"CP", "C", "*", "1"}, {"CP", "D", "*", "1"}, {"CP", "E", "*", "1"}, {"CP", "H", "*", "1"}, {"CP", "L", "*", "1"}, {"CP", "(HL)", "*", "2"}, {"CP", "A", "*", "1"},
	/* 0xcx */ {"RET", "NZ", "*", "2.5"}, {"POP", "BC", "*", "3"}, {"JP", "NZ", "a16", "1.333"}, {"JP", "a16", "*", "4"}, {"CALL", "NZ", "a16", "2"}, {"PUSH", "BC", "*", "4"}, {"ADD", "A", "d8", "2"}, {"RST", "00", "*", "4"}, {"RET", "Z", "*", "2.5"}, {"RET", "*", "*", "4"}, {"JP", "Z", "a16", "1.333"}, {"PREFIX CB", "*", "*", "1"}, {"CALL", "Z", "a16", "2"}, {"CALL", "a16", "*", "6"}, {"ADC", "A", "d8", "2"}, {"RST", "08", "*", "4"},
	/* 0xdx */ {"RET", "NC", "*", "2.5"}, {"POP", "DE", "*", "3"}, {"JP", "NC", "a16", "1.333"}, {"*", "*", "*", "*"}, {"CALL", "NC", "a16", "2"}, {"PUSH", "DE", "*", "4"}, {"SUB", "d8", "*", "2"}, {"RST", "16", "*", "4"}, {"RET", "C", "*", "2.5"}, {"RETI", "*", "*", "4"}, {"JP", "C", "a16", "1.333"}, {"*", "*", "*", "*"}, {"CALL", "C", "a16", "2"}, {"*", "*", "*", "*"}, {"SBC", "A", "d8", "2"}, {"RST", "24", "*", "4"},
	/* 0xex */ {"LDH", "(a8)", "A", "3"}, {"POP", "HL", "*", "3"}, {"LD", "(C)", "A", "2"}, {"*", "*", "*", "*"}, {"*", "*", "*", "*"}, {"PUSH", "HL", "*", "4"}, {"AND", "d8", "*", "2"}, {"RST", "32", "*", "4"}, {"ADD", "SP", "r8", "4"}, {"JP", "(HL)", "*", "1"}, {"LD", "(a16)", "A", "4"}, {"*", "*", "*", "*"}, {"*", "*", "*", "*"}, {"*", "*", "*", "*"}, {"XOR", "d8", "*", "2"}, {"RST", "40", "*", "4"},
	/* 0xfx */ {"LDH", "A", "(a8)", "3"}, {"POP", "AF", "*", "3"}, {"LD", "A", "(C)", "2"}, {"DI", "*", "*", "1"}, {"*", "*", "*", "*"}, {"PUSH", "AF", "*", "4"}, {"OR", "d8", "*", "2"}, {"RST", "48", "*", "4"}, {"LD", "HL", "SP+r8", "3"}, {"LD", "SP", "HL", "2"}, {"LD", "A", "(a16)", "4"}, {"EI", "*", "*", "1"}, {"*", "*", "*", "*"}, {"*", "*", "*", "*"}, {"CP", "d8", "*", "2"}, {"RST", "56", "*", "4"},
}

func disasm(opcode byte) string {
	result := ""

	mnemonic := mnemonics[opcode]
	for i := 0; i < 3; i++ {
		if mnemonic[i] == "*" {
			break
		}

		result += mnemonic[i] + " "
	}

	result = strings.TrimRight(result, " ")
	return result
}

func (d *Debugger) Disasm(w http.ResponseWriter, req *http.Request) {
	res, err := json.Marshal(Inst{
		PC:       fmt.Sprintf("0x%04x", d.g.Reg.PC),
		Mnemonic: disasm(d.g.Load8(d.g.Reg.PC)),
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(res)
}
