package mail

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"

	"codex-pool/internal/config"
)

// 默认邮箱配置
var defaultMailServices = []config.MailServiceConfig{
	{
		Name:       "esyteam",
		APIBase:    "https://mail.esyteam.edu.kg",
		APIToken:   "005d6f3e-5312-4c37-8125-e1f71243e1ba",
		Domain:     "esyteam.edu.kg",
		EmailPath:  "/api/public/emailList",
		AddUserAPI: "/api/public/addUser",
	},
}

// 全局变量
var (
	currentMailServices []config.MailServiceConfig
	mailServicesMutex   sync.RWMutex
	currentServiceIndex int
)

func init() {
	currentMailServices = defaultMailServices
}

// Init 初始化邮箱服务配置
func Init(services []config.MailServiceConfig) {
	mailServicesMutex.Lock()
	defer mailServicesMutex.Unlock()

	if len(services) > 0 {
		for i := range services {
			if services[i].EmailPath == "" {
				services[i].EmailPath = "/api/public/emailList"
			}
			if services[i].AddUserAPI == "" {
				services[i].AddUserAPI = "/api/public/addUser"
			}
			if services[i].Name == "" {
				services[i].Name = fmt.Sprintf("mail-service-%d", i+1)
			}
		}
		currentMailServices = services
		fmt.Printf("[邮箱] 已加载 %d 个邮箱服务配置:\n", len(services))
		for _, s := range services {
			fmt.Printf("  - %s (%s) @ %s\n", s.Name, s.Domain, s.APIBase)
		}
	} else {
		currentMailServices = defaultMailServices
		fmt.Println("[邮箱] 使用默认邮箱服务配置")
	}
	currentServiceIndex = 0
}

// GetServices 获取当前邮箱服务配置
func GetServices() []config.MailServiceConfig {
	mailServicesMutex.RLock()
	defer mailServicesMutex.RUnlock()
	return currentMailServices
}

// GetNextService 轮询获取下一个邮箱服务
func GetNextService() config.MailServiceConfig {
	mailServicesMutex.Lock()
	defer mailServicesMutex.Unlock()

	if len(currentMailServices) == 0 {
		return defaultMailServices[0]
	}

	service := currentMailServices[currentServiceIndex]
	currentServiceIndex = (currentServiceIndex + 1) % len(currentMailServices)
	return service
}

// GetRandomService 随机获取一个邮箱服务
func GetRandomService() config.MailServiceConfig {
	mailServicesMutex.RLock()
	defer mailServicesMutex.RUnlock()

	if len(currentMailServices) == 0 {
		return defaultMailServices[0]
	}

	return currentMailServices[rand.Intn(len(currentMailServices))]
}

// GetServiceByDomain 根据域名获取对应的邮箱服务
func GetServiceByDomain(domain string) *config.MailServiceConfig {
	mailServicesMutex.RLock()
	defer mailServicesMutex.RUnlock()

	for _, s := range currentMailServices {
		if s.Domain == domain || strings.HasSuffix(domain, "."+s.Domain) {
			return &s
		}
	}
	return nil
}

// ==================== 邮件结构 ====================

// EmailListRequest 邮件列表请求
type EmailListRequest struct {
	ToEmail  string `json:"toEmail"`
	TimeSort string `json:"timeSort"`
	Size     int    `json:"size"`
}

// EmailListResponse 邮件列表响应
type EmailListResponse struct {
	Code int         `json:"code"`
	Data []EmailItem `json:"data"`
}

// EmailItem 邮件项
type EmailItem struct {
	Content string `json:"content"`
	Text    string `json:"text"`
	Subject string `json:"subject"`
}

// AddUserRequest 创建用户请求
type AddUserRequest struct {
	List []AddUserItem `json:"list"`
}

// AddUserItem 用户项
type AddUserItem struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

// AddUserResponse 创建用户响应
type AddUserResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// ==================== 邮箱生成 ====================

// GenerateEmail 生成随机邮箱并在邮件系统中创建
func GenerateEmail() string {
	return GenerateEmailWithService(GetNextService())
}

// GenerateEmailWithService 使用指定服务生成随机邮箱
func GenerateEmailWithService(service config.MailServiceConfig) string {
	const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
	b := make([]byte, 10)
	for i := range b {
		b[i] = charset[rand.Intn(len(charset))]
	}
	email := string(b) + "@" + service.Domain

	if err := CreateMailboxWithService(email, service); err != nil {
		fmt.Printf("  [!] 创建邮箱失败 (%s): %v (继续尝试)\n", service.Name, err)
	}

	return email
}

// CreateMailbox 在邮件系统中创建邮箱
func CreateMailbox(email string) error {
	parts := strings.Split(email, "@")
	if len(parts) != 2 {
		return fmt.Errorf("无效的邮箱地址: %s", email)
	}

	domain := parts[1]
	service := GetServiceByDomain(domain)
	if service == nil {
		services := GetServices()
		if len(services) > 0 {
			service = &services[0]
		} else {
			return fmt.Errorf("没有可用的邮箱服务")
		}
	}

	return CreateMailboxWithService(email, *service)
}

// CreateMailboxWithService 使用指定服务在邮件系统中创建邮箱
func CreateMailboxWithService(email string, service config.MailServiceConfig) error {
	client := &http.Client{Timeout: 10 * time.Second}

	parts := strings.Split(email, "@")
	if len(parts) == 2 {
		domain := parts[1]
		if strings.HasSuffix(domain, "."+service.Domain) {
			email = parts[0] + "@" + service.Domain
		}
	}

	payload := AddUserRequest{
		List: []AddUserItem{
			{Email: email, Password: GeneratePassword()},
		},
	}
	jsonData, _ := json.Marshal(payload)

	req, err := http.NewRequest("POST", service.APIBase+service.AddUserAPI, bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", service.APIToken)
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var result AddUserResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return err
	}

	if result.Code != 200 {
		if strings.Contains(result.Message, "exist") {
			return nil
		}
		return fmt.Errorf("API 错误: %s", result.Message)
	}

	return nil
}

// GeneratePassword 生成随机密码
func GeneratePassword() string {
	const (
		upper   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		lower   = "abcdefghijklmnopqrstuvwxyz"
		digits  = "0123456789"
		special = "#$%@!"
	)

	password := make([]byte, 12)
	password[0] = upper[rand.Intn(len(upper))]
	password[1] = lower[rand.Intn(len(lower))]
	password[10] = digits[rand.Intn(len(digits))]
	password[11] = special[rand.Intn(len(special))]

	charset := upper + lower
	for i := 2; i < 10; i++ {
		password[i] = charset[rand.Intn(len(charset))]
	}

	return string(password)
}

// ==================== 邮件客户端 ====================

// Client 邮件客户端
type Client struct {
	client  *http.Client
	service *config.MailServiceConfig
}

// NewClient 创建邮件客户端
func NewClient() *Client {
	services := GetServices()
	var service *config.MailServiceConfig
	if len(services) > 0 {
		service = &services[0]
	} else {
		service = &defaultMailServices[0]
	}
	return &Client{
		client:  &http.Client{Timeout: 10 * time.Second},
		service: service,
	}
}

// NewClientWithService 创建指定服务的邮件客户端
func NewClientWithService(service config.MailServiceConfig) *Client {
	return &Client{
		client:  &http.Client{Timeout: 10 * time.Second},
		service: &service,
	}
}

// NewClientForEmail 根据邮箱地址创建对应的邮件客户端
func NewClientForEmail(email string) *Client {
	parts := strings.Split(email, "@")
	if len(parts) == 2 {
		if service := GetServiceByDomain(parts[1]); service != nil {
			return NewClientWithService(*service)
		}
	}
	return NewClient()
}

// GetEmails 获取邮件列表
func (m *Client) GetEmails(email string, size int) ([]EmailItem, error) {
	service := m.service
	parts := strings.Split(email, "@")
	if len(parts) == 2 {
		if s := GetServiceByDomain(parts[1]); s != nil {
			service = s
		}
	}

	url := service.APIBase + service.EmailPath

	payload := EmailListRequest{
		ToEmail:  email,
		TimeSort: "desc",
		Size:     size,
	}
	jsonData, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	req.Header.Set("Authorization", service.APIToken)
	req.Header.Set("Content-Type", "application/json")

	resp, err := m.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
	}

	var result EmailListResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}

	if result.Code != 200 {
		return nil, fmt.Errorf("API 错误: %d", result.Code)
	}

	return result.Data, nil
}

// WaitForCode 等待验证码邮件
func (m *Client) WaitForCode(email string, timeout time.Duration) (string, error) {
	start := time.Now()
	codeRegex := regexp.MustCompile(`\b(\d{6})\b`)

	for time.Since(start) < timeout {
		emails, err := m.GetEmails(email, 10)
		if err == nil {
			for _, mail := range emails {
				subject := strings.ToLower(mail.Subject)
				// 匹配多种可能的验证码邮件主题
				isCodeEmail := strings.Contains(subject, "code") ||
					strings.Contains(subject, "verify") ||
					strings.Contains(subject, "verification") ||
					strings.Contains(subject, "openai") ||
					strings.Contains(subject, "confirm")

				if !isCodeEmail {
					continue
				}

				content := mail.Content
				if content == "" {
					content = mail.Text
				}
				matches := codeRegex.FindStringSubmatch(content)
				if len(matches) >= 2 {
					return matches[1], nil
				}
			}
		}
		time.Sleep(2 * time.Second)
	}

	return "", fmt.Errorf("验证码获取超时")
}

// WaitForInviteLink 等待邀请邮件并提取链接
func (m *Client) WaitForInviteLink(email string, timeout time.Duration) (string, error) {
	start := time.Now()

	for time.Since(start) < timeout {
		emails, err := m.GetEmails(email, 10)
		if err == nil {
			for _, mail := range emails {
				content := mail.Content
				if content == "" {
					content = mail.Text
				}

				if strings.Contains(mail.Subject, "invite") ||
					strings.Contains(mail.Subject, "Team") ||
					strings.Contains(mail.Subject, "ChatGPT") ||
					strings.Contains(content, "invite") {

					link := extractInviteLink(content)
					if link != "" {
						return link, nil
					}
				}
			}
		}
		time.Sleep(2 * time.Second)
	}

	return "", fmt.Errorf("等待邀请邮件超时")
}

// extractInviteLink 从邮件内容提取邀请链接
func extractInviteLink(content string) string {
	patterns := []string{
		`https://chatgpt\.com/invite/[^\s"'<>]+`,
		`https://chat\.openai\.com/invite/[^\s"'<>]+`,
		`https://chatgpt\.com/[^\s"'<>]*accept[^\s"'<>]*`,
	}

	for _, pattern := range patterns {
		re := regexp.MustCompile(pattern)
		match := re.FindString(content)
		if match != "" {
			match = strings.ReplaceAll(match, "&amp;", "&")
			return match
		}
	}

	return ""
}

// ==================== 便捷函数 ====================

// WaitForInviteEmail 等待邀请邮件
func WaitForInviteEmail(email string, timeout time.Duration) (string, error) {
	client := NewClientForEmail(email)
	return client.WaitForInviteLink(email, timeout)
}

// GetVerificationCode 获取验证码
func GetVerificationCode(email string, timeout time.Duration) (string, error) {
	client := NewClientForEmail(email)
	return client.WaitForCode(email, timeout)
}
