package proxy

import (
	"bytes"
	"fmt"
	"sync"

	"cocogo/pkg/logger"
	"cocogo/pkg/model"
)

var (
	// Todo: Vim过滤依然存在问题
	vimEnterMark = []byte("\x1b[?25l\x1b[37;1H\x1b[1m")
	vimExitMark  = []byte("\x1b[37;1H\x1b[K\x1b")

	zmodemRecvStartMark = []byte("rz waiting to receive.**\x18B0100")
	zmodemSendStartMark = []byte("**\x18B00000000000000")
	zmodemCancelMark    = []byte("\x18\x18\x18\x18\x18")
	zmodemEndMark       = []byte("**\x18B0800000000022d")
	zmodemStateSend     = "send"
	zmodemStateRecv     = "recv"

	charEnter = []byte("\r")
)

// Parse 解析用户输入输出, 拦截过滤用户输入输出
type Parser struct {
	inputBuf  *bytes.Buffer
	cmdBuf    *bytes.Buffer
	outputBuf *bytes.Buffer

	cmdFilterRules []model.SystemUserFilterRule

	inputInitial  bool
	inputPreState bool
	inputState    bool
	zmodemState   string
	inVimState    bool
	once          sync.Once

	command         string
	output          string
	cmdInputParser  *CmdParser
	cmdOutputParser *CmdParser
	counter         int
}

func (p *Parser) Initial() {
	p.inputBuf = new(bytes.Buffer)
	p.cmdBuf = new(bytes.Buffer)
	p.outputBuf = new(bytes.Buffer)

	p.once = sync.Once{}

	p.cmdInputParser = &CmdParser{}
	p.cmdOutputParser = &CmdParser{}
	p.cmdInputParser.Initial()
	p.cmdOutputParser.Initial()
}

// Todo: parseMultipleInput 依然存在问题

// parseInputState 切换用户输入状态
func (p *Parser) parseInputState(b []byte) {
	if p.inVimState || p.zmodemState != "" {
		return
	}
	p.inputPreState = p.inputState
	if bytes.Contains(b, charEnter) {
		p.inputState = false
		p.parseCmdInput()
	} else {
		p.inputState = true
		if !p.inputPreState {
			p.parseCmdOutput()
		}
	}
}

func (p *Parser) parseCmdInput() {
	parser := CmdParser{}
	parser.Initial()
	data := p.cmdBuf.Bytes()
	line := parser.Parse(data)
	data2 := fmt.Sprintf("[%d] 命令: %s\n", p.counter, line)
	fmt.Printf(data2)
	p.cmdBuf.Reset()
	p.inputBuf.Reset()
	p.counter += 1
}

func (p *Parser) parseCmdOutput() {
	data := p.outputBuf.Bytes()
	line := p.cmdOutputParser.Parse(data)
	data2 := fmt.Sprintf("[%d] 结果: %s\n", p.counter, line)
	_ = fmt.Sprintf("[%d] 结果: %s\n", p.counter, line)
	fmt.Printf(data2)
	p.outputBuf.Reset()
}

func (p *Parser) parseInputNewLine(b []byte) []byte {
	b = bytes.Replace(b, []byte{'\r', '\r', '\n'}, []byte{'\r'}, -1)
	b = bytes.Replace(b, []byte{'\r', '\n'}, []byte{'\r'}, -1)
	b = bytes.Replace(b, []byte{'\n'}, []byte{'\r'}, -1)
	return b
}

func (p *Parser) ParseUserInput(b []byte) []byte {
	p.once.Do(func() {
		p.inputInitial = true
	})
	nb := p.parseInputNewLine(b)
	p.inputBuf.Write(nb)
	p.parseInputState(nb)
	return b
}

func (p *Parser) parseVimState(b []byte) {
	if p.zmodemState == "" && !p.inVimState && bytes.Contains(b, vimEnterMark) {
		p.inVimState = true
		logger.Debug("In vim state: true")
	}
	if p.zmodemState == "" && p.inVimState && bytes.Contains(b, vimExitMark) {
		p.inVimState = false
		logger.Debug("In vim state: false")
	}
}

func (p *Parser) parseZmodemState(b []byte) {
	if len(b) < 25 {
		return
	}
	if p.zmodemState == "" {
		if len(b) > 50 && bytes.Contains(b[:50], zmodemRecvStartMark) {
			p.zmodemState = zmodemStateRecv
			logger.Debug("Zmodem in recv state")
		} else if bytes.Contains(b[:24], zmodemSendStartMark) {
			p.zmodemState = zmodemStateSend
			logger.Debug("Zmodem in send state")
		}
	} else {
		if bytes.Contains(b[:24], zmodemEndMark) {
			logger.Debug("Zmodem end")
			p.zmodemState = ""
		} else if bytes.Contains(b[:24], zmodemCancelMark) {
			logger.Debug("Zmodem cancel")
			p.zmodemState = ""
		}
	}
}

func (p *Parser) parseCommand(b []byte) {
	if !p.inputInitial {
		return
	}
	if p.inputState {
		p.cmdBuf.Write(b)
	} else {
		p.outputBuf.Write(b)
	}
}

func (p *Parser) ParseServerOutput(b []byte) []byte {
	p.parseVimState(b)
	p.parseZmodemState(b)
	p.parseCommand(b)
	return b
}

func (p *Parser) SetCMDFilterRules(rules []model.SystemUserFilterRule) {
	p.cmdFilterRules = rules
}

func (p *Parser) SetReplayRecorder() {

}

func (p *Parser) SetCommandRecorder() {

}