package chess

import "fmt"

type Piece string

const (
	White = "W"
	Black = "B"
	R     = "R"
	N     = "N"
	S     = "S"
	M     = "M"
	K     = "K"
	Q     = "Q"
	P     = "P"

	WR Piece = "WR"
	WN Piece = "WN"
	WS Piece = "WS"
	WM Piece = "WM"
	WK Piece = "WK"
	WQ Piece = "WQ"
	WP Piece = "WP"
	BR Piece = "BR"
	BN Piece = "BN"
	BS Piece = "BS"
	BM Piece = "BM"
	BK Piece = "BK"
	BQ Piece = "BQ"
	BP Piece = "BP"
	EM Piece = ""
)

func IsWhite(p Piece) bool {
	if IsEmpty(p) {
		return false
	}
	return p[0] == 'W'
}

func IsBlack(p Piece) bool {
	if IsEmpty(p) {
		return false
	}
	return p[0] == 'B'
}

func IsEmpty(p Piece) bool {
	return p == "" || p == " " || p == "  " || p == "."
}

func IsR(p Piece) bool {
	return len(p) == 2 && p[1] == 'R'
}

func IsN(p Piece) bool {
	return len(p) == 2 && p[1] == 'N'
}

func IsS(p Piece) bool {
	return len(p) == 2 && p[1] == 'S'
}

func IsM(p Piece) bool {
	return len(p) == 2 && p[1] == 'M'
}

func IsK(p Piece) bool {
	return len(p) == 2 && p[1] == 'K'
}

func IsQ(p Piece) bool {
	return len(p) == 2 && p[1] == 'Q'
}

func IsP(p Piece) bool {
	return len(p) == 2 && p[1] == 'P'
}

func ToPiece(color, chessType string) Piece {
	if color != White && color != Black {
		return ""
	}
	return Piece(fmt.Sprint(color, chessType))
}

func XYToIndex(width, height, x, y int) (int, error) {
	if x < 0 || x >= width || y < 0 || y >= height {
		return -1, fmt.Errorf("坐标超出范围")
	}

	return y*width + x, nil
}

func IndexToXY(width, height, index int) (int, int, error) {
	if index < 0 || index >= width*height {
		return -1, -1, fmt.Errorf("索引超出范围")
	}

	x := index % width
	y := index / width

	return x, y, nil
}

// Position 坐标
type Position struct {
	X, Y int
}

// PositionPiece 坐标及这个坐标存在的棋子
type PositionPiece struct {
	Index int   // 坐标
	P     Piece // 被吃的对方棋子
}

type Logic interface {
	// Init 重置棋盘
	Init()
	// GetWidth 获取宽度
	GetWidth() int
	// GetHeight 获取高度
	GetHeight() int
	// GetChess 获取棋子数据
	GetChess() []string
	// GetAct 获取该谁走
	GetAct() string
	// GetCastling 王车易位可行性
	GetCastling() []bool
	// GetEnPassant 过路兵位置
	GetEnPassant() int
	// GetCambodianMove 获取柬埔寨象棋王士特殊走子状态
	GetCambodianMove() []bool
	// GetRound 获取回合数
	GetRound() int
	// GetPiece 获取棋子
	GetPiece(index int) Piece
	// GetChessNum 获取棋子数量
	GetChessNum(piece Piece) int
	// GetWhiteNum 获取白子数量
	GetWhiteNum() int
	// GetBlackNum 获取黑子数量
	GetBlackNum() int
	// Has 是否有棋子
	Has(piece Piece) bool
	// GetVariant 获取规则类型
	GetVariant() int

	// GetMovePositions 获取指定索引位置的棋子能走的位置
	GetMovePositions(index int) []*PositionPiece
	// GetMoveAllPositions 所有可移动棋子及位置
	GetMoveAllPositions(isWhite bool) [][2]*PositionPiece
	// GetIndexes 获取指定棋子的位置
	GetIndexes(p Piece) []int
	// IsCheck 判断将军
	IsCheck(isWhite bool) bool
	// IsCheckmate 判断将死
	IsCheckmate(isWhite bool) bool
	// Move 移动棋子
	Move(fromIndex, toIndex int) *PositionPiece
	// MoveBack 悔棋一步
	MoveBack() bool
	// CanMove 判断是否可以移动
	CanMove(fromIndex, toIndex int) bool
	// IsStop 判断无子可走
	IsStop(isWhite bool) bool
	// IsWhiteMove 是否该白旗走
	IsWhiteMove() bool
	// IsBlackMove 是否该黑棋字走
	IsBlackMove() bool

	// GetCheck 获取将军状态
	GetCheck() []bool
	// GetCheckmate 获取将死状态
	GetCheckmate() []bool
	// NextAct 切换对方操作
	NextAct()

	// SetChess 设置棋盘
	SetChess([]string)
	// Set 设置数据
	Set(bufStr []string, bufPiece []Piece, act string, castling []bool, cambodianMove []bool, enPassant int, round int)
	// PrintChess 打印
	PrintChess()
	// GenFen fen记谱法
	GenFen() string
	// UciTwoPosToIdxList ai
	UciTwoPosToIdxList(fromTo string) []int64
}

const (
	ChessVarChess int = iota
	ChessVarMakruk
	ChessVarCambodian
)

func NewChess(v int) Logic {
	switch v {
	case ChessVarChess, ChessVarMakruk, ChessVarCambodian:
		return new(ChessJPZ)
	default:
		return new(ChessJPZ)
	}
}
