package fileutil

import (
	"bufio"
	"errors"
	"os"
	"regexp"
	"strconv"
	"strings"
	log "tiloader/pkg/logutil"
)

const (
	REPLACE int = iota // a = 0
	APPEND             // b = 1
)

type DescFile struct {
	DataFileName string    //数据文件名称
	TableName    string    //表名
	Method       int       //方式--换成枚举/整型
	Cols         []ColInfo //列
	Charset      string    //字符编码
}

type ColInfo struct {
	ColName       string //列名
	PositionStart int    //起始位置
	PositionEnd   int    //结束位置
}

type DescFileParser struct {
}

func (descFileParser DescFileParser) Parse(path string) (DescFile, error) {
	descFile := DescFile{}
	log.WriteLog("desc config file :" + path)
	//打开文件
	file, err := os.OpenFile(path, os.O_RDWR, 0666)
	if err != nil {
		log.WriteLog("Open desc file error!" + path)
		//返回error
		return descFile, err
	}
	defer file.Close()
	log.WriteLog("parse desc file begin")

	scanner := bufio.NewScanner(file)
	//行数
	count := 0
	//描述文件结束标记
	end_flag := false

	//定义一个可变长数组
	s1 := []ColInfo{}
	//循环读取每一行文件
tag1:
	for {
		if !scanner.Scan() {
			break //文件读完了,退出for
		}
		//两端去除空格
		line := scanner.Text() //获取每一行
		line = strings.TrimSpace(line)
		count++
		//开始正则表达式配置
		//正则表达式1，从配置中读取
		switch count {
		case 1:
			//第一行什么也不做
		case 2:
			//charset
			expstr := `(?i:^charset) +(\S+)$`
			match, err := regexp.MatchString(expstr, line)
			if err != nil || match != true {
				return descFile, errors.New("parse file error,The second line should be formatted like \"charset utf8mb4\"")
			}
			charsetRegexp := regexp.MustCompile(expstr)
			result2 := charsetRegexp.FindStringSubmatch(line)[1]
			descFile.Charset = result2
		case 3:
			//第三行验证格式
			match, err := regexp.MatchString(`(?i:^INFILE) +'(\S+)'$`, line)
			if err != nil || match != true {
				return descFile, errors.New("parse file error,The third line should be formatted like \"INFILE 'data.txt'\"")
			}
			//第三行取出数据文件名字
			fileNameRegexp := regexp.MustCompile(`(?i:^INFILE) +'(\S+)'$`)
			result1 := fileNameRegexp.FindStringSubmatch(line)[1]
			descFile.DataFileName = result1
		case 4:
			//第四行取出Method
			switch strings.ToUpper(line) {
			case "REPLACE":
				descFile.Method = REPLACE
			case "APPEND":
				descFile.Method = APPEND
			default:
				log.WriteLog("parse file error,the method is invalid input")
				//返回error
				return descFile, errors.New("parse file error,the method is invalid input")
			}
		case 5:
			//第五行验证格式
			match, err := regexp.MatchString(`(?i:^INTO +TABLE) +(\S+)$`, line)
			if err != nil || match != true {
				return descFile, errors.New("parse file error,The fifth line should be formatted like \"INTO TABLE db1.t1\"")
			}
			//第五行取出TableName
			tableNameRegexp := regexp.MustCompile(`(?i:^INTO +TABLE) +(\S+)$`)
			result2 := tableNameRegexp.FindStringSubmatch(line)[1]
			descFile.TableName = result2
		default:
			//寻找关键字position,如果有position就取值，没有进入后续判断
			flag := strings.Contains(strings.ToUpper(line), "POSITION")
			if flag == true {
				//通过正则获取列名
				colNameRegexp := regexp.MustCompile(`^[\w|\S]+`)
				result3 := colNameRegexp.FindStringSubmatch(line)
				//通过正则获取position前后数字
				//position (25:30)
				col2NameRegexp := regexp.MustCompile(`(?i:position)\s+\((.*?)\)`)
				result4 := col2NameRegexp.FindStringSubmatch(line)
				//由于第一个包含了(，需要特殊处理去掉
				if result3[0][0:1] == "(" {
					result3[0] = strings.Trim(result3[0], "(")
				}
				result6 := strings.Split(result4[1], ":")
				pStart, err1 := strconv.Atoi(result6[0])
				pEnd, err2 := strconv.Atoi(result6[1])
				//将结果放入ColInfo
				if err1 != nil || err2 != nil {
					log.WriteLog("parse positionStart error")
					return descFile, errors.New("parse positionStart error")
				}
				//判断end必须大于等于start
				if pEnd < pStart {
					log.WriteLog(result3[0] + " The end position cannot be smaller than the start position")
					return descFile, errors.New("parse positionStart error")
				}
				s1 = append(s1, ColInfo{result3[0], pStart, pEnd})
			} else {
				//没有关键字position，判断是否是右括号
				if line == ")" {
					end_flag = true
					break tag1
				} else {
					return descFile, errors.New("parse file error,The file does not end with a close parenthesis")
				}
			}
		}
	}
	if !end_flag {
		return descFile, errors.New("parse file error,The file does not end with a close parenthesis")
	}
	descFile.Cols = s1[:]
	log.WriteLog("parse desc file done")
	return descFile, nil
}
