package resource

import (
	"errors"
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-message/charset"
	"github.com/emersion/go-message/mail"
	"hongze/fms_api/global"
	"hongze/fms_api/utils"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"time"
)

type EmailImapService struct {
	Client *client.Client
}

func NewEmailImapService() *EmailImapService {
	global.LOG.Info("Connecting to server...")

	// Connect to server
	//c, err := client.DialTLS("imap.qq.com:993", nil)
	var emailHost string
	if global.CONFIG.Serve.RunMode != "debug" {
		emailHost = "imap.qiye.aliyun.com:993"
	} else {
		//测试邮箱
		emailHost = "imap.aliyun.com:993"
	}
	c, err := client.DialTLS(emailHost, nil)
	if err != nil {
		panic("连接邮箱服务器失败:" + err.Error())
	}
	global.LOG.Info("Connected success")
	return &EmailImapService{Client: c}
}

type AttachmentListItem struct {
	Title      string
	Date       time.Time
	Name       string
	Position   string
	FullPath   string
	FileName   string
	FromEmails []string
	LoadUrl    string
}

//DownLoadCv 下载简历附件接口
func (e *EmailImapService) DownLoadEmailCv(username, password string, attachmentChan chan *AttachmentListItem) (err error) {
	// Don't forget to logout
	defer e.Client.Logout()
	defer close(attachmentChan)

	// Login
	if err = e.Client.Login(username, password); err != nil {
		global.LOG.Info("login failed err: " + err.Error())
		return
	}

	global.LOG.Info("login in")
	// Select INBOX
	mbox, err := e.Client.Select("INBOX", false)
	if err != nil {
		global.LOG.Error(err)
		return
	}

	// Get the last message
	if mbox.Messages == 0 {
		global.LOG.Error("No message in mailbox")
		return
	}
	/*// 筛选最近7天的邮件
	//criteria := imap.NewSearchCriteria()
	//criteria.WithoutFlags = []string{imap.SeenFlag}
	//criteria.SentSince = time.Date(1984, 11, 5, 0, 0, 0, 0, time.UTC)
	//ids, err := e.Client.Search(criteria)

	if err != nil {
		global.LOG.Error("No search message in mailbox"+err.Error())
		return
	}
	if len(ids) == 0 {
		global.LOG.Error("No search message in mailbox")
		return
	}
	seqSet := new(imap.SeqSet)
	seqSet.AddNum(ids...)*/
	seqSet := new(imap.SeqSet)
	from := uint32(1)
	to := mbox.Messages
	if mbox.Messages > 100 {
		// We're using unsigned integers here, only subtract if the result is > 0
		from = mbox.Messages - 100
	}
	seqSet.AddRange(from, to)
	global.LOG.Infof("mbox.Messages length :%d", mbox.Messages)

	// Get the whole message body
	var section imap.BodySectionName
	items := []imap.FetchItem{section.FetchItem()}

	messages := make(chan *imap.Message, mbox.Messages)
	done := make(chan error, 1)
	go func() {
		done <- e.Client.Fetch(seqSet, items, messages)
	}()
	global.LOG.Info("最近7天收到的邮件:")
	imap.CharsetReader = charset.Reader
	beforeDate7 := time.Now().AddDate(0, 0, -7)
	for msg := range messages {
		if msg == nil {
			err = errors.New("Server didn't returned message")
			global.LOG.Error("Server didn't returned message")
			return
		}
		tmp := new(AttachmentListItem)
		section = imap.BodySectionName{}
		r := msg.GetBody(&section)
		if r == nil {
			err = errors.New("Server didn't returned message body")
			global.LOG.Error("Server didn't returned message body")
			return
		}
		var mr *mail.Reader
		mr, err = mail.CreateReader(r)
		if err != nil {
			global.LOG.Error(err)
			return
		}

		// Print some info about the message
		header := mr.Header
		var emailDate time.Time
		if emailDate, err = header.Date(); err == nil {
			global.LOG.Infof("Date:%s", emailDate.Format(utils.FormatDateTime))
			if emailDate.Before(beforeDate7) {
				continue
			}
			//global.LOG.Infof("Date:", emailDate)
			tmp.Date = emailDate
		}
		if subject, err := header.Subject(); err == nil {
			global.LOG.Infof("Subject:%s", subject)
			newSubject, info, flag := DealSubject(subject)
			if !flag {
				continue
			}
			tmp.Title = newSubject
			tmp.Name = info.Name
			tmp.Position = info.Position
		}
		if from, err := header.AddressList("From"); err == nil {
			global.LOG.Infof("From:%s", from)
			//tmp.SenderEmails = from
			for _, fa := range from {
				tmp.FromEmails = append(tmp.FromEmails, fa.Address)
			}
		}
		if to, err := header.AddressList("To"); err == nil {
			global.LOG.Infof("To:%s", to)
		}

		// Process each message's part
		for {
			p, tErr := mr.NextPart()
			if tErr == io.EOF {
				break
			} else if tErr != nil {
				global.LOG.Errorf("Process each message's part err:%v", tErr)
				return
			}

			switch h := p.Header.(type) {
			case *mail.InlineHeader:
				// This is the message's text (can be plain-text or HTML)
				_, _ = ioutil.ReadAll(p.Body)
				//global.LOG.Infof("Got text: %v", string(b))
			case *mail.AttachmentHeader:
				// This is an attachment
				filename, _ := h.Filename()
				tmp.FileName = filename
				global.LOG.Infof("Got attachment: %v", filename)
				//保存到本地
				dir, tmpErr := mk_dir("download/cv/" + emailDate.Format(utils.FormatDateTimeUnSpace))
				if tmpErr != nil {
					err = tmpErr
					global.LOG.Infof("%v 写入失败 err %s", filename, err.Error())
					return
				}
				filename = dir + "/" + filename
				content, _ := ioutil.ReadAll(p.Body)
				//global.LOG.Infof("Got text: %v", string(content))
				err = write_to_file(filename, content)
				if err != nil {
					global.LOG.Infof("%v 写入失败", filename)
					return
				}
				tmp.FullPath = filename

				/*tmpFileName := strings.Split(path.Base(tmp.FileName), ".")
				tmpName := tmpFileName[0]
				ext := tmpFileName[1]
				global.LOG.Infof("Got attachment ext: %v", ext)
				if ext == "docx" {
					fileOutPath, e := FuncDocs2Pdf(global.CONFIG.Serve.LibreOfficePath, filename ,dir,"pdf")
					if e != nil {
						err = e
						global.LOG.Infof("docx 转pdf 失败:%v",e.Error())
						return
					}
					tmp.FullPath = fileOutPath
					tmp.FileName = tmpName + ".pdf"
				}*/
				//把结果放到channel中
				attachmentChan <- tmp
			}
		}
	}

	if err = <-done; err != nil {
		global.LOG.Info("email client Fetch Err: " + err.Error())
		return
	}
	return
}

func mk_dir(dir_path string) (string, error) {
	var path string
	if os.IsPathSeparator('\\') { //前边的判断是否是系统的分隔符
		path = "\\"
	} else {
		path = "/"
	}
	//fmt.Println(path)
	dir, _ := os.Getwd()                               //当前的目录
	err := os.MkdirAll(dir+path+dir_path, os.ModePerm) //在当前目录下生成md目录
	if err != nil {
		global.LOG.Infof("%v", err)
		return "", nil
	}
	return dir + path + dir_path, nil
}

/*
	函数名称:write_to_file
	函数作用:写内容到文件
	输入参数:filename(文件名),content(内容)
	输出参数:无
*/

func write_to_file(filename string, content []byte) (err error) {
	var fileHandle *os.File
	/*if !checkFileIsExist(filename) { //如果文件存在
		fileHandle, err = os.Create(filename) //创建文件
		global.LOG.Infof("文件不存在")
		if err != nil {
			global.LOG.Infof("Err" + err.Error())
		}
	}else{*/
	fileHandle, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm)
	//global.LOG.Infof("文件存在")
	//}
	if err != nil {
		return
	}

	defer fileHandle.Close()
	//循环读取

	// NewWriter 默认缓冲区大小是 4096
	// 需要使用自定义缓冲区的writer 使用 NewWriterSize()方法
	//	buf := bufio.NewWriter(fileHandle)
	// 字节写入
	// 字符串写入
	_, err = fileHandle.WriteString(string(content))
	if err != nil {
		return
	}

	return
}

func DealSubject(subject string) (newSubject string, person AttachmentListItem, flag bool) {
	if strings.Contains(subject, "转发:") || strings.Contains(subject, "Fwd:") {
		reg := `^[Fwd:|转发:]+`
		re := regexp.MustCompile(reg)
		subject = re.ReplaceAllString(subject, "")
	}
	newSubject = subject
	person, flag = dealBossSubject(subject)
	if !flag {
		person, flag = dealDefaultSubject(subject)
		if !flag {
			person, flag = dealLiePinSubject(subject)
			if !flag {
				person, flag = dealOtherSubject(subject)
			}
		}
	}
	return
}

func dealBossSubject(subject string) (person AttachmentListItem, flag bool) {
	matched, err := regexp.MatchString(`(.*)【BOSS直聘】`, subject)
	if err != nil {
		return
	}
	if !matched {
		return
	}
	items := strings.Split(subject, "|")
	if len(items) < 3 {
		return
	}
	name := items[0]
	global.LOG.Infof("求职姓名:%s", name)
	//获取职位
	items1 := strings.Split(items[1], "应聘")
	if len(items1) < 2 {
		return
	}
	position := strings.Trim(items1[1], " ")
	global.LOG.Infof("求职岗位:%s", position)
	person.Name = name
	person.Position = position
	flag = true
	return
}

func dealDefaultSubject(subject string) (person AttachmentListItem, flag bool) {
	reg := `[(](.*)[)-](.*){1,10}[先生|女士]$`
	matched, err := regexp.MatchString(reg, subject)
	if err != nil {
		return
	}
	if !matched {
		return
	}
	re := regexp.MustCompile(reg)
	position := re.ReplaceAllString(subject, "")
	global.LOG.Infof("求职岗位:%s", position)
	if position == "" {
		return
	}
	//获取职位
	items := strings.Split(subject, "-")
	if len(items) < 2 {
		return
	}

	name := items[len(items)-1]
	global.LOG.Infof("求职姓名:%s", name)
	person.Name = name
	person.Position = position
	flag = true
	return
}

func dealLiePinSubject(subject string) (person AttachmentListItem, flag bool) {
	reg := `来自猎聘的候选人`
	matched, err := regexp.MatchString(reg, subject)
	if err != nil {
		return
	}
	if !matched {
		return
	}
	// Regex pattern captures "key: value" pair from the content.
	pattern := regexp.MustCompile("【(?P<key1>(.*)+)_(?P<key2>(.*)+)】(?P<key3>(.*)+)_(?P<key4>(.*)+)")

	// Template to convert "key: value" to "key=value" by
	// referencing the values captured by the regex pattern.
	template := "$key1=$key2=$key3=$key4\n"

	result := []byte{}

	// For each match of the regex in the content.
	for _, submatches := range pattern.FindAllStringSubmatchIndex(subject, -1) {
		// Apply the captured submatches to the template and append the output
		// to the result.
		result = pattern.ExpandString(result, template, subject, submatches)
	}
	global.LOG.Infof("求职邮件匹配结果:%s", string(result))
	//获取职位
	tmp := strings.Split(string(result), "=")
	if len(tmp) < 4 {
		return
	}

	position := strings.Trim(tmp[0], " ")
	global.LOG.Infof("求职岗位:%s", position)
	name := strings.Trim(tmp[2], " ")
	global.LOG.Infof("求职姓名:%s", name)
	person.Name = name
	person.Position = position
	flag = true
	return
}

func dealOtherSubject(subject string) (person AttachmentListItem, flag bool) {
	reg := `^New application`
	matched, err := regexp.MatchString(reg, subject)
	if err != nil {
		return
	}
	if !matched {
		return
	}
	// Regex pattern captures "key: value" pair from the content.
	pattern := regexp.MustCompile(`(?P<key1>[a-zA-z\s]+)from(?P<key2>[a-zA-z\s]+)`)

	// Template to convert "key: value" to "key=value" by
	// referencing the values captured by the regex pattern.
	template := "$key1=$key2\n"

	result := []byte{}

	// For each match of the regex in the content.
	for _, submatches := range pattern.FindAllStringSubmatchIndex(subject, -1) {
		// Apply the captured submatches to the template and append the output
		// to the result.
		result = pattern.ExpandString(result, template, subject, submatches)
	}
	global.LOG.Infof("求职邮件匹配结果:%s", string(result))
	//获取职位
	tmp := strings.Split(string(result), "=")
	if len(tmp) < 2 {
		return
	}

	position := strings.Trim(tmp[0], " ")
	global.LOG.Infof("求职岗位:%s", position)
	name := strings.Trim(tmp[1], " ")
	global.LOG.Infof("求职姓名:%s", name)
	person.Name = name
	person.Position = position
	flag = true
	return
}