package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/tealeg/xlsx"
	"golang.org/x/crypto/bcrypt"
)

// GenerateAdminHashedPassword [管理端]生成密码
func GenerateAdminHashedPassword(password string) (string, error) {
	salt := "7M&7p7euU=CC"
	passwordWithSalt := password + salt

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(passwordWithSalt), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}

	return string(hashedPassword), nil
}

// VerifyAdminHashedPassword [管理端]验证密码
func VerifyAdminHashedPassword(hashedPassword, password string) bool {
	salt := "7M&7p7euU=CC"
	passwordWithSalt := password + salt

	err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(passwordWithSalt))
	return err == nil
}

// ToExcel 生成 Excel
func ToExcel(titleList []string, dataList []interface{}) []byte {
	// 生成一个新的文件
	file := xlsx.NewFile()

	// 添加sheet页
	sheet, _ := file.AddSheet("Sheet1")

	// 插入表头
	titleRow := sheet.AddRow()
	for _, v := range titleList {
		cell := titleRow.AddCell()
		cell.Value = v
	}

	// 插入内容
	for _, v := range dataList {
		row := sheet.AddRow()
		row.WriteStruct(v, -1)
	}

	var buffer bytes.Buffer
	_ = file.Write(&buffer)
	return buffer.Bytes()
}

func MD5(text string) string {
	hash := md5.New()
	hash.Write([]byte(text))
	hashBytes := hash.Sum(nil)
	return hex.EncodeToString(hashBytes)
}

// GetIP 尝试从 HTTP 请求中获取真实的客户端 IP 地址
func GetIP(r *http.Request) string {
	// 从 X-Forwarded-For 头部获取IP地址
	xForwardedFor := r.Header.Get("X-Forwarded-For")
	if xForwardedFor != "" {
		// 可能有多个IP地址，通常第一个是客户端的真实IP
		ips := strings.Split(xForwardedFor, ",")
		if len(ips) > 0 {
			return strings.TrimSpace(ips[0])
		}
	}

	// 如果没有 X-Forwarded-For 头部，尝试从 X-Real-IP 获取
	xRealIP := r.Header.Get("X-Real-IP")
	if xRealIP != "" {
		return strings.TrimSpace(xRealIP)
	}

	// 如果没有代理头部，最后退回到 RemoteAddr
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		// 如果处理RemoteAddr出错，返回空字符串
		return ""
	}
	return ip
}

// FriendlyTimeAgo 友好时间
func FriendlyTimeAgo(date time.Time) string {
	now := time.Now()

	if date.After(now) {
		return "未来的日期"
	}

	diff := now.Sub(date)
	minutes := int(diff.Minutes())
	hours := int(diff.Hours())
	days := int(hours / 24)

	// 小于1分钟
	if minutes < 1 {
		return "刚刚"
	}

	// 小于1小时
	if hours < 1 {
		return fmt.Sprintf("%d分钟", minutes)
	}

	// 小于1天
	if hours < 24 {
		return fmt.Sprintf("%d小时", hours)
	}

	// 小于1周
	if days < 7 {
		return fmt.Sprintf("%d天", days)
	}

	// 小于1个月
	if days < 30 {
		return fmt.Sprintf("%d周", days/7)
	}

	// 小于1年
	if days < 365 {
		months := int(days / 30)
		if months < 1 {
			return fmt.Sprintf("%d天", days)
		}

		return fmt.Sprintf("%d个月", months)
	}

	// 大于等于1年
	years := days / 365
	remainingDays := days % 365
	months := remainingDays / 30

	if months == 0 {
		return fmt.Sprintf("%d年", years)
	}
	return fmt.Sprintf("%d年%d个月", years, months)
}

// FriendlySubTime 时间相减
func FriendlySubTime(birthday, date time.Time) string {
	diff := date.Sub(birthday)
	minutes := int(diff.Minutes())
	hours := int(diff.Hours())
	days := int(hours / 24)

	// 小于1分钟
	if minutes < 1 {
		return "刚刚"
	}

	// 小于1小时
	if hours < 1 {
		return fmt.Sprintf("%d分钟", minutes)
	}

	// 小于1天
	if hours < 24 {
		return fmt.Sprintf("%d小时", hours)
	}

	// 小于1周
	if days < 7 {
		return fmt.Sprintf("%d天", days)
	}

	// 小于1个月
	if days < 30 {
		return fmt.Sprintf("%d周", days/7)
	}

	// 小于1年
	if days < 365 {
		months := int(days / 30)
		if months < 1 {
			return fmt.Sprintf("%d天", days)
		}

		return fmt.Sprintf("%d个月", months)
	}

	// 大于等于1年
	years := days / 365
	remainingDays := days % 365
	months := remainingDays / 30

	if months == 0 {
		return fmt.Sprintf("%d岁", years)
	}
	return fmt.Sprintf("%d岁%d个月", years, months)
}

func XorEncrypt(phone, key string) string {
	result := make([]byte, len(phone))
	for i := 0; i < len(phone); i++ {
		result[i] = phone[i] ^ key[i%len(key)]
	}
	return base64.StdEncoding.EncodeToString(result)
}

func XorDecrypt(encrypted, key string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		return "", err
	}

	result := make([]byte, len(data))
	for i := 0; i < len(data); i++ {
		result[i] = data[i] ^ key[i%len(key)]
	}
	return string(result), nil
}

// TruncateRunes truncates a string to the specified rune limit
func TruncateRunes(s string, limit int) string {
	runes := []rune(s)
	if len(runes) > limit {
		return string(runes[:limit])
	}
	return s
}

// TruncateBytes truncates a string to the specified byte limit while ensuring valid UTF-8
func TruncateBytes(s string, limit int) string {
	if len(s) <= limit {
		return s
	}
	var b int
	for i, r := range s {
		rl := len(string(r))
		if b+rl > limit {
			return s[:i]
		}
		b += rl
	}
	return s
}
