package cloudflare

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"

	"agent-wdd/log"
)

const (
	// CloudflareAPIBaseURL is the base URL for Cloudflare API
	CloudflareAPIBaseURL = "https://api.cloudflare.com/client/v4"
	// DefaultTimeout is the default timeout for HTTP requests
	DefaultTimeout = 5 * time.Second
)

// CloudflareClient represents a client for interacting with Cloudflare API
type CloudflareClient struct {
	apiToken       string
	baseURL        string
	client         *http.Client
	userAgent      string
	dnsNameToIDMap map[string]string // 域名到ID的映射
}

var (
	instance *CloudflareClient
	once     sync.Once
)

// Response is the general response structure from Cloudflare API
type Response struct {
	Result     interface{}   `json:"result"`
	ResultInfo *ResultInfo   `json:"result_info,omitempty"`
	Success    bool          `json:"success"`
	Errors     []Error       `json:"errors"`
	Messages   []interface{} `json:"messages"`
}

// ResultInfo contains pagination information
type ResultInfo struct {
	Page       int `json:"page"`
	PerPage    int `json:"per_page"`
	TotalPages int `json:"total_pages"`
	Count      int `json:"count"`
	TotalCount int `json:"total_count"`
}

// Error represents an error returned by the Cloudflare API
type Error struct {
	Code       int     `json:"code"`
	Message    string  `json:"message"`
	ErrorChain []Error `json:"error_chain,omitempty"`
}

// NewClient creates a new instance of CloudflareClient with the given API token
func NewClient(apiToken string) *CloudflareClient {
	log.Debug("Creating new Cloudflare client")
	return &CloudflareClient{
		apiToken:  apiToken,
		baseURL:   CloudflareAPIBaseURL,
		client:    &http.Client{Timeout: DefaultTimeout},
		userAgent: "WddSuperAgent/1.0",
	}
}

// GetInstance returns the singleton instance of CloudflareClient
func GetInstance(apiToken string) *CloudflareClient {
	if instance == nil {
		once.Do(func() {
			instance = NewClient(apiToken)
			log.Info("Cloudflare client singleton instance created")
		})
	}
	return instance
}

// SetAPIToken updates the API token used for authentication
func (c *CloudflareClient) SetAPIToken(apiToken string) {
	c.apiToken = apiToken
	log.Info("Cloudflare API token updated")
}

// SetTimeout updates the HTTP client timeout
func (c *CloudflareClient) SetTimeout(timeout time.Duration) {
	c.client.Timeout = timeout
	log.Info("Cloudflare client timeout updated to %v", timeout)
}

// doRequest performs an HTTP request with the given method, URL, and body
func (c *CloudflareClient) doRequest(method, url string, body interface{}) (*Response, error) {
	log.Debug("Performing %s request to %s", method, url)

	var reqBody io.Reader
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			log.Error("Failed to marshal request body: %v", err)
			return nil, fmt.Errorf("failed to marshal request body: %w", err)
		}
		reqBody = bytes.NewBuffer(jsonBody)
	}

	req, err := http.NewRequest(method, url, reqBody)
	if err != nil {
		log.Error("Failed to create HTTP request: %v", err)
		return nil, fmt.Errorf("failed to create HTTP request: %w", err)
	}

	// Set headers
	req.Header.Set("Authorization", "Bearer "+c.apiToken)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", c.userAgent)

	// Perform request
	resp, err := c.client.Do(req)
	if err != nil {
		log.Error("Failed to execute HTTP request: %v", err)
		return nil, fmt.Errorf("failed to execute HTTP request: %w", err)
	}
	defer resp.Body.Close()

	// Read response body
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Error("Failed to read response body: %v", err)
		return nil, fmt.Errorf("failed to read response body: %w", err)
	}

	// Parse response
	var cfResp Response
	if err := json.Unmarshal(respBody, &cfResp); err != nil {
		log.Error("Failed to unmarshal response: %v", err)
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}

	// Check for API errors
	if !cfResp.Success {
		errorMsg := "Cloudflare API error"
		if len(cfResp.Errors) > 0 {
			errorMsg = fmt.Sprintf("%s: %s (code: %d)", errorMsg, cfResp.Errors[0].Message, cfResp.Errors[0].Code)
		}
		log.Error(errorMsg)
		return &cfResp, fmt.Errorf(errorMsg)
	}

	log.Debug("Request completed successfully")
	return &cfResp, nil
}

// GetDNSNameToIDMap 获取域名到ID的映射
func (c *CloudflareClient) GetDNSNameToIDMap(zoneID string) map[string]string {

	// 如果dnsNameToIDMap为空，则获取所有域名到ID的映射
	if c.dnsNameToIDMap == nil {
		c.ListDNSRecords(zoneID, nil)
	}

	return c.dnsNameToIDMap
}
