package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"io"
	"math/rand"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"
)

var Username = flag.String("u", "", "统一认证学号/用户名")
var Password = flag.String("p", "", "统一认证密码")
var evaluationChan = make(chan struct{}, 3)
var waitGroup = sync.WaitGroup{}

func main() {
	rand.Seed(time.Now().UnixNano())
	flag.Parse()
	if *Username == "" || *Password == "" {
		flag.Usage()
		return
	}
	fmt.Println("正在登入系统...")
	res, err := Client.Do(createRequest("GET", "http://bkzhjx.wh.sdu.edu.cn/sso.jsp", nil))
	_ = checkHttpError(res, err)
	casUrl := "https://pass.sdu.edu.cn/cas/login?service=http%3A%2F%2Fbkzhjx.wh.sdu.edu.cn%2Fsso.jsp"
	res, err = Client.Do(createRequest("GET", casUrl, nil))
	err = checkHttpError(res, err)
	if err != nil {
		panic(err)
	}
	html, _ := io.ReadAll(res.Body)
	ticket := regexp.MustCompile("name=\"lt\" value=\"(.*?)\"").FindStringSubmatch(string(html))[1]
	rsa := strEnc(*Username + *Password + ticket)
	loginValues := url.Values{
		"rsa":       {rsa},
		"ul":        {strconv.Itoa(utf8.RuneCountInString(*Username))},
		"pl":        {strconv.Itoa(utf8.RuneCountInString(*Password))},
		"lt":        {ticket},
		"execution": {"e1s1"},
		"_eventId":  {"submit"},
	}
	res, err = Client.Do(createRequest("POST", casUrl, strings.NewReader(loginValues.Encode())))
	err = checkHttpError(res, err)
	if err != nil {
		panic(err)
	}
	html, _ = io.ReadAll(res.Body)
	if !strings.Contains(string(html), "强智科技教务系统欢迎") && !strings.Contains(string(html), "进入选课") {
		fmt.Println("用户名或密码错误")
		return
	}
	fmt.Println("登入系统成功")
	res, err = Client.Do(createRequest("GET", "https://bkzhjx.wh.sdu.edu.cn/jsxsd/xspj/xspj_find.do", nil))
	err = checkHttpError(res, err)
	if err != nil {
		panic(err)
	}
	html, _ = io.ReadAll(res.Body)
	evaluationLink := "https://bkzhjx.wh.sdu.edu.cn" + regexp.MustCompile("<a href=\"(.*?)\" title=\"点击进入评价\"").FindStringSubmatch(string(html))[1]
	res, err = Client.Do(createRequest("GET", evaluationLink, nil))
	err = checkHttpError(res, err)
	if err != nil {
		panic(err)
	}
	tableDocument, _ := goquery.NewDocumentFromReader(res.Body)
	tableDocument.Find("table tr").Each(func(i int, selection *goquery.Selection) {
		htmlOfTr, _ := selection.Html()
		if strings.Contains(htmlOfTr, "Nsb_r_list_thb") {
			return
		}
		tdSelection := selection.Find("td")
		var tds []string
		tdSelection.Each(func(i int, selection *goquery.Selection) {
			h, _ := selection.Html()
			tds = append(tds, h)
		})
		if tds[7] == "是" {
			fmt.Println(tds[2] + " 已评，自动忽略")
			return
		}
		evaluationFullURL := "https://bkzhjx.wh.sdu.edu.cn" + regexp.MustCompile("<a href=\"(.*?)\">评价").FindStringSubmatch(htmlOfTr)[1]
		evaluationFullURL = strings.ReplaceAll(evaluationFullURL, "&amp;", "&")
		waitGroup.Add(1)
		go evaluateByURL(tds[2], evaluationFullURL)
	})
	waitGroup.Wait()
}
func evaluateByURL(course string, fullURL string) {
	evaluationChan <- struct{}{}
	defer func() {
		<-evaluationChan
		waitGroup.Done()
	}()
	fmt.Println("正在评教：" + course)
	res, err := Client.Do(createRequest("GET", fullURL, nil))
	err = checkHttpError(res, err)
	if err != nil {
		fmt.Printf("评教 "+course+" 出错：%+v", err)
		return
	}
	html, _ := io.ReadAll(res.Body)
	postData := url.Values{
		"issubmit": {"1"},
		"kctzdnd":  {"3"},
		"yxjspx":   {"1"},
		"isxtjg":   {"1"},
		"jynr":     {"课程良好"},
	}
	for _, key := range []string{"pj09id", "pj01id", "pj0502id", "jg0101id", "jx0404id", "xsflid", "xnxq01id", "jx02id", "pj02id", "ifypjxx", "pj03id", "pageIndex"} {
		addStdHiddenFormValue(string(html), &postData, key)
	}
	doc, _ := goquery.NewDocumentFromReader(strings.NewReader(string(html)))
	degree := 2
	doc.Find("table tr").Each(func(i int, selection *goquery.Selection) {
		htmlOfTr, _ := selection.Html()
		if !strings.Contains(htmlOfTr, "pj06xh") {
			return
		}
		pj06ix := addStdHiddenFormValue(htmlOfTr, &postData, "pj06xh")
		var selectedHash string
		for _, item := range []int{1, 2, 3, 4, 5} {
			hash, _ := selection.Find("input[id=pj0601id_" + pj06ix + "_" + strconv.Itoa(item) + "]").Attr("value")
			currentScore, _ := selection.Find("input[name=pj0601fz_" + pj06ix + "_" + hash + "]").Attr("value")
			postData.Add("pj0601fz_"+pj06ix+"_"+hash, currentScore)
			if degree == item {
				selectedHash = hash
			}
		}
		postData.Add("pj0601id_"+pj06ix, selectedHash)
		if degree == 2 {
			degree = 1
		}
	})
	res, err = Client.Do(createRequest("POST", "https://bkzhjx.wh.sdu.edu.cn/jsxsd/xspj/xspj_save.do", strings.NewReader(postData.Encode())))
	err = checkHttpError(res, err)
	if err != nil {
		fmt.Printf("评教 "+course+" 出错：%+v", err)
		return
	}
	html, _ = io.ReadAll(res.Body)
	if !strings.Contains(string(html), "成功") {
		fmt.Printf("评教 "+course+" 出错：%+v", err)
		fmt.Println(string(html))
		return
	}
}
func addStdHiddenFormValue(html string, obj *url.Values, key string) string {
	value := regexp.MustCompile("input type=\"hidden\" name=\"" + key + "\" value=\"(.*?)\"").FindStringSubmatch(html)[1]
	obj.Add(key, value)
	return value
}
