package main

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

func strToDateTime(str string) time.Time {
	dt, err := time.Parse("2006-01-02 15:04:05", str)
	if err == nil {
		return dt
	} else {
		panic(any(err))
	}
}

func strToDate(str string) time.Time {
	date, err := time.Parse("2006-01-02", str)
	if err == nil {
		return date
	} else {
		panic(any(err))
	}
}

func strToTime(str string) time.Time {
	timeStr := str
	if timeStr == "" {
		timeStr = "00:00"
	}
	tm, err := time.Parse("15:04", timeStr)
	if err == nil {
		return tm
	} else {
		panic(any(err))
	}
}

func dateTimeToStr(time time.Time) string {
	return time.Format("2006-01-02 15:04:05")
}

func dateToStr(time time.Time) string {
	return time.Format("2006-01-02")
}

func timeToStr(time time.Time) string {
	return time.Format("15:04")
}

func dateTimeToTime(datetime time.Time) time.Time {
	return strToTime(timeToStr(datetime))
}

func dateTimeToDate(datetime time.Time) time.Time {
	return strToDate(dateToStr(datetime))
}

func NewUUId() string {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		panic(any(err))
	}
	return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

func readBody(resp *http.Response) []byte {
	defer resp.Body.Close()
	contentLength := resp.ContentLength
	if contentLength == -1 {
		bodyData, err := io.ReadAll(resp.Body)
		if err == nil {
			return bodyData
		} else {
			panic(any(err))
		}
	} else {
		buffer := new(bytes.Buffer)
		for contentLength > 0 {
			size, err := buffer.ReadFrom(resp.Body)
			if err == nil {
				contentLength -= size
			} else {
				break
			}
		}
		bodyData := buffer.Bytes()
		return bodyData
	}
}

func calcPerformanceHours(rules AttendanceRules, data AttendanceData) float64 {
	if data.State == 出差 {
		return 8
	}
	if data.State == 缺卡 {
		return 0
	}
	if data.State == 休息 {
		return 0
	}
	if data.State == 请假 {
		if (data.StartTime.Hour() == 0 && data.StartTime.Minute() == 0) || (data.EndTime.Hour() == 0 && data.EndTime.Minute() == 0) {
			return 0
		}
	}
	start := data.StartTime
	if data.EndTime.Before(start) {
		return 0
	}
	hours := data.EndTime.Sub(start).Hours()
	if hours > 100 {
		Logger.log(WarningLevel, "Calc hours error, it larger than 100")
	}
	if start.Hour() < 12 {
		hours -= 1
	}
	overEndMinutes := data.EndTime.Sub(rules.End).Minutes()
	if overEndMinutes > 30 {
		hours -= 0.5
	}
	if hours < 0 {
		return 0
	}
	return hours
}

func calcWorkingHours(day time.Time, rules AttendanceRules, data AttendanceData, isHoliday bool, holidayAdjusted bool, isNationalLegalHoliday bool) float64 {
	if day.Weekday() == time.Saturday || day.Weekday() == time.Sunday || isHoliday {
		//法定节假日来加班都不算
		if isHoliday && !holidayAdjusted && isNationalLegalHoliday {
			return 0
		}
		//节假日/周末/调班休息日计算方式
		if data.State == 加班 {
			return 0
		} else {
			//最早 7:30
			earliestStart := strToTime("7:30")
			start := data.StartTime
			if start.Sub(earliestStart).Minutes() < 0 {
				start = earliestStart
			}
			if data.EndTime.Before(start) {
				return 0
			}
			hours := data.EndTime.Sub(start).Hours()
			//12点前来的，扣掉中饭时间和晚饭时间
			if start.Hour() < 12 {
				hours -= 1.5
			}
			if hours < 7.5 {
				return 0
			}
			return 7.5
		}
	}
	if data.EndResult == "请假" {
		return 0
	}

	start := data.StartTime
	if start.Sub(rules.Start).Minutes() < 0 {
		start = rules.Start
	}

	if (start.Hour() > 12 && start.Hour() < 13) || (data.StartResult == "请假") {
		start = strToTime("13:00")
	}

	if data.EndTime.Before(start) {
		return 0
	}
	hours := data.EndTime.Sub(start).Hours()

	if hours > 100 {
		Logger.log(WarningLevel, "Calc hours error, it larger than 100")
	}

	//12点前来的，扣掉中饭时间
	if start.Hour() < 12 {
		hours -= 1
	}
	overEndMinutes := data.EndTime.Sub(rules.End).Minutes()
	if overEndMinutes > 30 {
		hours -= 0.5
	}
	if hours < 0 {
		return 0
	}
	return hours
}

func calcRequiredWorkingHours(day time.Time, rules AttendanceRules, data AttendanceData, isHoliday bool) float64 {
	if day.Weekday() == time.Saturday || day.Weekday() == time.Sunday || isHoliday {
		return 0
	}
	start := rules.Start
	if data.StartResult == "正常" {
		if (data.StartTime.Hour() > 12 && data.StartTime.Hour() < 13) || (data.StartTime.Hour() > 13) {
			start = strToTime("13:00")
		}
	}

	if data.StartResult == "请假" {
		start = strToTime("13:00")
	}

	requiredHours := rules.End.Sub(start).Hours()

	//12点前来的，扣掉中饭时间
	if start.Hour() < 12 {
		requiredHours -= 1
	}
	return requiredHours
}

func b64(str string) string {
	return "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(str)) + "?="
}

func sendEmail(host string, port string, sender string, password string, receiver string, cc string, title string, content string) {
	receivers := make([]string, 0)
	temp := strings.Split(receiver, ";")
	for i := 0; i < len(temp); i++ {
		if temp[i] != "" {
			receivers = append(receivers, temp[i])
		}
	}
	toStr := strings.Join(receivers, ",")

	ccs := make([]string, 0)
	temp = strings.Split(cc, ";")
	for i := 0; i < len(temp); i++ {
		if temp[i] != "" {
			ccs = append(ccs, temp[i])
		}
	}
	var message []byte
	if len(ccs) == 0 {
		message = []byte("From: " + sender + "\r\n" +
			"To: " + toStr + "\r\n" +
			"Subject: " + b64(title) + "\r\n\r\n" +
			content + "\r\n")
	} else {
		ccStr := strings.Join(ccs, ",")
		message = []byte("From: " + sender + "\r\n" +
			"To: " + toStr + "\r\n" +
			"cc: " + ccStr + "\r\n" +
			"Subject: " + b64(title) + "\r\n\r\n" +
			content + "\r\n")
	}
	// Authentication.
	auth := NewLoginAuth(sender, password, host)
	for i := 0; i < len(ccs); i++ {
		receivers = append(receivers, ccs[i])
	}
	err := SendMail(host+":"+port, auth, sender, receivers, message)
	if err != nil {
		Logger.log(WarningLevel, err.Error())
	}
}
