package cert_manager_wdd

import (
	"agent-wdd/cloudflare"
	"agent-wdd/log"
	"context"
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"encoding/pem"

	"golang.org/x/crypto/acme"
)

// ACMEClient ACME协议客户端
type ACMEClient struct {
	client     *acme.Client
	account    *acme.Account
	accountKey crypto.Signer
	directory  string
	email      string
	cfAPI      *cloudflare.CloudflareClient
}

// NewACMEClient 创建新的ACME客户端
//
// 参数:
//   - directory: ACME服务器目录URL
//   - email: 注册账户的邮箱
//   - cfAPI: Cloudflare API客户端
//
// 返回:
//   - *ACMEClient: ACME客户端
//   - error: 错误信息
func NewACMEClient(directory, email string, cfAPI *cloudflare.CloudflareClient) (*ACMEClient, error) {
	log.Debug("创建ACME客户端，目录: %s, 邮箱: %s", directory, email)

	// 创建客户端
	client := &acme.Client{
		DirectoryURL: directory,
	}

	// 生成账户密钥
	accountKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Error("生成ACME账户密钥失败: %v", err)
		return nil, fmt.Errorf("生成ACME账户密钥失败: %w", err)
	}

	acmeClient := &ACMEClient{
		client:     client,
		accountKey: accountKey,
		directory:  directory,
		email:      email,
		cfAPI:      cfAPI,
	}

	// 注册账户
	if err := acmeClient.registerAccount(); err != nil {
		log.Error("ACME账户注册失败: %v", err)
		return nil, fmt.Errorf("ACME账户注册失败: %w", err)
	}

	return acmeClient, nil
}

// registerAccount 注册ACME账户
func (ac *ACMEClient) registerAccount() error {
	log.Debug("注册ACME账户")

	// 创建上下文
	ctx := context.Background()

	// 设置账户密钥
	ac.client.Key = ac.accountKey

	// 注册新账户
	account := &acme.Account{
		Contact: []string{"mailto:" + ac.email},
	}
	account, err := ac.client.Register(ctx, account, acme.AcceptTOS)
	if err != nil {
		// 错误处理，特别处理已存在账户的情况
		if err.(*acme.Error).StatusCode == 409 {
			log.Info("ACME账户已存在，已重新获取")
			// 获取现有账户
			account, err = ac.client.GetReg(ctx, "")
			if err != nil {
				return fmt.Errorf("获取现有ACME账户失败: %w", err)
			}
		} else {
			return fmt.Errorf("注册ACME账户失败: %w", err)
		}
	}

	ac.account = account
	log.Info("ACME账户注册/获取成功")
	return nil
}

// ObtainCertificate 获取证书
//
// 参数:
//   - domain: 需要申请证书的域名
//   - privateKey: 证书私钥
//   - certDir: 证书保存目录
//
// 返回:
//   - *CertInfo: 证书信息
//   - error: 错误信息
func (ac *ACMEClient) ObtainCertificate(domain string, privateKey crypto.Signer, certDir string) (*CertInfo, error) {
	log.Info("开始获取域名 %s 的证书", domain)

	// 创建上下文
	ctx := context.Background()

	// 创建新订单
	order, err := ac.client.AuthorizeOrder(ctx, []acme.AuthzID{
		{Type: "dns", Value: domain},
	})
	if err != nil {
		log.Error("创建ACME订单失败: %v", err)
		return nil, fmt.Errorf("创建ACME订单失败: %w", err)
	}

	// 处理授权
	for _, authzURL := range order.AuthzURLs {
		authz, err := ac.client.GetAuthorization(ctx, authzURL)
		if err != nil {
			log.Error("获取授权信息失败: %v", err)
			return nil, fmt.Errorf("获取授权信息失败: %w", err)
		}

		// 查找DNS挑战
		var challenge *acme.Challenge
		for _, c := range authz.Challenges {
			if c.Type == "dns-01" {
				challenge = c
				break
			}
		}

		if challenge == nil {
			log.Error("未找到DNS-01挑战")
			return nil, fmt.Errorf("未找到DNS-01挑战")
		}

		// 获取TXT记录值
		txtValue, err := ac.client.DNS01ChallengeRecord(challenge.Token)
		if err != nil {
			log.Error("获取DNS-01挑战记录失败: %v", err)
			return nil, fmt.Errorf("获取DNS-01挑战记录失败: %w", err)
		}

		// 使用Cloudflare API设置DNS TXT记录
		if err := ac.setDNSChallengeTXT(domain, txtValue); err != nil {
			log.Error("设置DNS TXT记录失败: %v", err)
			return nil, fmt.Errorf("设置DNS TXT记录失败: %w", err)
		}

		// 等待DNS传播
		log.Info("等待DNS记录传播...")
		time.Sleep(30 * time.Second)

		// 通知ACME服务器完成挑战
		if _, err := ac.client.Accept(ctx, challenge); err != nil {
			log.Error("接受挑战失败: %v", err)
			return nil, fmt.Errorf("接受挑战失败: %w", err)
		}

		// 等待授权完成
		_, err = ac.client.WaitAuthorization(ctx, authzURL)
		if err != nil {
			log.Error("等待授权完成失败: %v", err)
			return nil, fmt.Errorf("等待授权完成失败: %w", err)
		}

		// 清理DNS记录
		if err := ac.cleanupDNSChallenge(domain); err != nil {
			log.Warning("清理DNS TXT记录失败: %v", err)
			// 不中断流程，继续申请证书
		}
	}

	// 创建CSR
	csr, err := createCSR(privateKey, domain)
	if err != nil {
		log.Error("创建CSR失败: %v", err)
		return nil, fmt.Errorf("创建CSR失败: %w", err)
	}

	// 完成订单
	certDERs, _, err := ac.client.CreateOrderCert(ctx, order.FinalizeURL, csr, true)
	if err != nil {
		log.Error("完成订单失败: %v", err)
		return nil, fmt.Errorf("完成订单失败: %w", err)
	}

	// 处理证书
	var pemData []byte
	for _, der := range certDERs {
		b := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
		pemData = append(pemData, b...)
	}

	// 保存证书
	certPath := filepath.Join(certDir, "cert.pem")
	if err := os.WriteFile(certPath, pemData, 0644); err != nil {
		log.Error("保存证书失败: %v", err)
		return nil, fmt.Errorf("保存证书失败: %w", err)
	}

	// 解析证书以获取详细信息
	cert, err := parseCertificate(certPath)
	if err != nil {
		log.Error("解析保存的证书失败: %v", err)
		return nil, fmt.Errorf("解析保存的证书失败: %w", err)
	}

	// 构建证书信息
	keyPath := filepath.Join(certDir, "private.key")
	certInfo := &CertInfo{
		Domain:        domain,
		RegisteredAt:  cert.NotBefore,
		ExpiresAt:     cert.NotAfter,
		CertPath:      certPath,
		KeyPath:       keyPath,
		CAName:        getCertCAName(cert),
		NeedsRenewal:  false,
		WildcardCert:  strings.HasPrefix(domain, "*."),
		DaysRemaining: int(cert.NotAfter.Sub(time.Now()).Hours() / 24),
	}

	log.Info("证书获取成功: %s", domain)
	return certInfo, nil
}

// setDNSChallengeTXT 设置DNS TXT记录用于ACME验证
func (ac *ACMEClient) setDNSChallengeTXT(domain, txtValue string) error {
	log.Debug("设置DNS TXT记录: %s", domain)

	// 处理域名，提取主域名和记录名
	recordName := fmt.Sprintf("_acme-challenge.%s", domain)
	if strings.HasPrefix(domain, "*.") {
		// 通配符域名处理
		recordName = fmt.Sprintf("_acme-challenge.%s", domain[2:])
	}

	// 获取域名的zone信息
	zones, err := ac.cfAPI.ListZones(nil)
	if err != nil {
		return fmt.Errorf("获取Cloudflare zones失败: %w", err)
	}

	var zoneID string
	for _, zone := range zones {
		if strings.HasSuffix(domain, zone.Name) || strings.HasSuffix(domain[2:], zone.Name) {
			zoneID = zone.ID
			break
		}
	}

	if zoneID == "" {
		return fmt.Errorf("未找到域名 %s 的Cloudflare Zone", domain)
	}

	// 创建TXT记录
	record := cloudflare.DNSRecord{
		Type:    "TXT",
		Name:    recordName,
		Content: txtValue,
		TTL:     120,
	}

	_, err = ac.cfAPI.CreateDNSRecord(zoneID, record)
	if err != nil {
		return fmt.Errorf("创建DNS TXT记录失败: %w", err)
	}

	log.Info("DNS TXT记录已创建: %s", recordName)
	return nil
}

// cleanupDNSChallenge 清理DNS验证记录
func (ac *ACMEClient) cleanupDNSChallenge(domain string) error {
	log.Debug("清理DNS TXT记录: %s", domain)

	// 处理域名，提取主域名和记录名
	recordName := fmt.Sprintf("_acme-challenge.%s", domain)
	if strings.HasPrefix(domain, "*.") {
		// 通配符域名处理
		recordName = fmt.Sprintf("_acme-challenge.%s", domain[2:])
	}

	// 获取域名的zone信息
	zones, err := ac.cfAPI.ListZones(nil)
	if err != nil {
		return fmt.Errorf("获取Cloudflare zones失败: %w", err)
	}

	var zoneID string
	for _, zone := range zones {
		if strings.HasSuffix(domain, zone.Name) || strings.HasSuffix(domain[2:], zone.Name) {
			zoneID = zone.ID
			break
		}
	}

	if zoneID == "" {
		return fmt.Errorf("未找到域名 %s 的Cloudflare Zone", domain)
	}

	// 查找TXT记录
	filter := &cloudflare.DNSRecordFilter{
		Type: "TXT",
		Name: recordName,
	}

	records, err := ac.cfAPI.ListDNSRecords(zoneID, filter)
	if err != nil {
		return fmt.Errorf("查找DNS TXT记录失败: %w", err)
	}

	// 删除匹配的记录
	for _, record := range records {
		if record.Name == recordName && record.Type == "TXT" {
			_, err = ac.cfAPI.DeleteDNSRecord(zoneID, record.ID)
			if err != nil {
				return fmt.Errorf("删除DNS TXT记录失败: %w", err)
			}
			log.Info("DNS TXT记录已删除: %s", recordName)
		}
	}

	return nil
}

// createCSR 创建证书签名请求
func createCSR(privateKey crypto.Signer, domain string) ([]byte, error) {
	template := &x509.CertificateRequest{
		Subject: pkix.Name{
			CommonName: domain,
		},
	}

	// 处理通配符域名
	if strings.HasPrefix(domain, "*.") {
		template.DNSNames = []string{domain, domain[2:]}
	} else {
		template.DNSNames = []string{domain}
	}

	csrDER, err := x509.CreateCertificateRequest(rand.Reader, template, privateKey)
	if err != nil {
		return nil, err
	}

	return csrDER, nil
}
