package cloudflare

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	"agent-wdd/log"
)

// DNSRecord represents a DNS record in Cloudflare
type DNSRecord struct {
	ID                string                 `json:"id,omitempty"`
	Name              string                 `json:"name"`
	Type              string                 `json:"type"`
	Content           string                 `json:"content"`
	Priority          int                    `json:"priority,omitempty"`
	Proxiable         bool                   `json:"proxiable,omitempty"`
	Proxied           bool                   `json:"proxied"`
	TTL               int                    `json:"ttl"`
	Settings          map[string]interface{} `json:"settings,omitempty"`
	Meta              map[string]interface{} `json:"meta,omitempty"`
	Comment           string                 `json:"comment,omitempty"`
	Tags              []string               `json:"tags,omitempty"`
	CreatedOn         string                 `json:"created_on,omitempty"`
	ModifiedOn        string                 `json:"modified_on,omitempty"`
	CommentModifiedOn string                 `json:"comment_modified_on,omitempty"`
}

// DNSRecordFilter represents filters for listing DNS records
type DNSRecordFilter struct {
	Type      string
	Name      string
	Content   string
	Page      int
	PerPage   int
	Order     string
	Direction string
	Match     string
}

// ListDNSRecords retrieves all DNS records for a zone
//
// Parameters:
//   - zoneID: The zone ID
//   - filter: Optional filter to apply to the DNS records list
//
// Returns:
//   - []DNSRecord: List of DNS records
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) ListDNSRecords(zoneID string, filter *DNSRecordFilter) ([]DNSRecord, error) {
	log.Debug("Listing DNS records for zone ID: %s with filter: %+v", zoneID, filter)

	// Build URL and query parameters
	endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID)
	u, err := url.Parse(endpoint)
	if err != nil {
		log.Error("Failed to parse URL: %v", err)
		return nil, fmt.Errorf("failed to parse URL: %w", err)
	}

	q := u.Query()
	if filter != nil {
		if filter.Type != "" {
			q.Add("type", filter.Type)
		}
		if filter.Name != "" {
			q.Add("name", filter.Name)
		}
		if filter.Content != "" {
			q.Add("content", filter.Content)
		}
		if filter.Page > 0 {
			q.Add("page", strconv.Itoa(filter.Page))
		}
		if filter.PerPage > 0 {
			q.Add("per_page", strconv.Itoa(filter.PerPage))
		}
		if filter.Order != "" {
			q.Add("order", filter.Order)
		}
		if filter.Direction != "" {
			q.Add("direction", filter.Direction)
		}
		if filter.Match != "" {
			q.Add("match", filter.Match)
		}
	}
	u.RawQuery = q.Encode()

	// Make request
	resp, err := c.doRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		log.Error("Failed to list DNS records: %v", err)
		return nil, fmt.Errorf("failed to list DNS records: %w", err)
	}

	// Parse response
	var records []DNSRecord
	result, err := json.Marshal(resp.Result)
	if err != nil {
		log.Error("Failed to marshal result: %v", err)
		return nil, fmt.Errorf("failed to marshal result: %w", err)
	}

	if err := json.Unmarshal(result, &records); err != nil {
		log.Error("Failed to unmarshal DNS records: %v", err)
		return nil, fmt.Errorf("failed to unmarshal DNS records: %w", err)
	}

	// 将域名和ID的映射关系存储到dnsNameToIDMap中
	c.dnsNameToIDMap = make(map[string]string, len(records))
	for _, record := range records {
		c.dnsNameToIDMap[record.Name] = record.ID
	}

	log.Info("Successfully retrieved %d DNS records for zone ID: %s", len(records), zoneID)
	return records, nil
}

// CreateDNSRecord creates a new DNS record in the specified zone
//
// Parameters:
//   - zoneID: The zone ID
//   - record: The DNS record to create
//
// Returns:
//   - *DNSRecord: The created DNS record
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) CreateDNSRecord(zoneID string, record DNSRecord) (*DNSRecord, error) {
	log.Debug("Creating DNS record in zone ID: %s with data: %+v", zoneID, record)

	// Build URL
	endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID)

	// Make request
	resp, err := c.doRequest(http.MethodPost, endpoint, record)
	if err != nil {
		log.Error("Failed to create DNS record: %v", err)
		return nil, fmt.Errorf("failed to create DNS record: %w", err)
	}

	// Parse response
	var createdRecord DNSRecord
	result, err := json.Marshal(resp.Result)
	if err != nil {
		log.Error("Failed to marshal result: %v", err)
		return nil, fmt.Errorf("failed to marshal result: %w", err)
	}

	if err := json.Unmarshal(result, &createdRecord); err != nil {
		log.Error("Failed to unmarshal created DNS record: %v", err)
		return nil, fmt.Errorf("failed to unmarshal created DNS record: %w", err)
	}

	log.Info("Successfully created DNS record: %s (%s) in zone ID: %s", createdRecord.Name, createdRecord.ID, zoneID)
	return &createdRecord, nil
}

// GetDNSRecord retrieves a specific DNS record by ID
//
// Parameters:
//   - zoneID: The zone ID
//   - recordID: The DNS record ID
//
// Returns:
//   - *DNSRecord: The DNS record
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) GetDNSRecord(zoneID, recordID string) (*DNSRecord, error) {
	log.Debug("Getting DNS record ID: %s in zone ID: %s", recordID, zoneID)

	// Build URL
	endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)

	// Make request
	resp, err := c.doRequest(http.MethodGet, endpoint, nil)
	if err != nil {
		log.Error("Failed to get DNS record: %v", err)
		return nil, fmt.Errorf("failed to get DNS record: %w", err)
	}

	// Parse response
	var record DNSRecord
	result, err := json.Marshal(resp.Result)
	if err != nil {
		log.Error("Failed to marshal result: %v", err)
		return nil, fmt.Errorf("failed to marshal result: %w", err)
	}

	if err := json.Unmarshal(result, &record); err != nil {
		log.Error("Failed to unmarshal DNS record: %v", err)
		return nil, fmt.Errorf("failed to unmarshal DNS record: %w", err)
	}

	log.Info("Successfully retrieved DNS record: %s (%s) from zone ID: %s", record.Name, record.ID, zoneID)
	return &record, nil
}

// UpdateDNSRecord updates an existing DNS record
//
// Parameters:
//   - zoneID: The zone ID
//   - recordID: The DNS record ID
//   - record: The updated DNS record data
//
// Returns:
//   - *DNSRecord: The updated DNS record
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) UpdateDNSRecord(zoneID, recordID string, record DNSRecord) (*DNSRecord, error) {
	log.Debug("Updating DNS record ID: %s in zone ID: %s with data: %+v", recordID, zoneID, record)

	// Build URL
	endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)

	// Make request
	resp, err := c.doRequest(http.MethodPut, endpoint, record)
	if err != nil {
		log.Error("Failed to update DNS record: %v", err)
		return nil, fmt.Errorf("failed to update DNS record: %w", err)
	}

	// Parse response
	var updatedRecord DNSRecord
	result, err := json.Marshal(resp.Result)
	if err != nil {
		log.Error("Failed to marshal result: %v", err)
		return nil, fmt.Errorf("failed to marshal result: %w", err)
	}

	if err := json.Unmarshal(result, &updatedRecord); err != nil {
		log.Error("Failed to unmarshal updated DNS record: %v", err)
		return nil, fmt.Errorf("failed to unmarshal updated DNS record: %w", err)
	}

	log.Info("Successfully updated DNS record: %s (%s) in zone ID: %s", updatedRecord.Name, updatedRecord.ID, zoneID)
	return &updatedRecord, nil
}

// DeleteDNSRecord deletes a DNS record
//
// Parameters:
//   - zoneID: The zone ID
//   - recordID: The DNS record ID
//
// Returns:
//   - bool: True if the record was deleted successfully
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) DeleteDNSRecord(zoneID, recordID string) (bool, error) {
	log.Debug("Deleting DNS record ID: %s in zone ID: %s", recordID, zoneID)

	// Build URL
	endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID)

	// Make request
	resp, err := c.doRequest(http.MethodDelete, endpoint, nil)
	if err != nil {
		log.Error("Failed to delete DNS record: %v", err)
		return false, fmt.Errorf("failed to delete DNS record: %w", err)
	}

	// Parse response
	result, ok := resp.Result.(map[string]interface{})
	if !ok {
		log.Error("Unexpected response format for DNS record deletion")
		return false, fmt.Errorf("unexpected response format for DNS record deletion")
	}

	id, ok := result["id"].(string)
	if !ok {
		log.Error("Failed to extract ID from deletion response")
		return false, fmt.Errorf("failed to extract ID from deletion response")
	}

	log.Info("Successfully deleted DNS record ID: %s from zone ID: %s", id, zoneID)
	return true, nil
}

// FindDNSRecord finds a DNS record by name and type
//
// Parameters:
//   - zoneID: The zone ID
//   - name: The DNS record name
//   - recordType: The DNS record type (A, AAAA, CNAME, etc.)
//
// Returns:
//   - *DNSRecord: The found DNS record, or nil if not found
//   - error: Any errors that occurred during the request
func (c *CloudflareClient) FindDNSRecord(zoneID, name, recordType string) (*DNSRecord, error) {
	log.Debug("Finding DNS record with name: %s and type: %s in zone ID: %s", name, recordType, zoneID)

	filter := &DNSRecordFilter{
		Name: name,
		Type: recordType,
	}

	records, err := c.ListDNSRecords(zoneID, filter)
	if err != nil {
		return nil, err
	}

	if len(records) == 0 {
		log.Warning("No DNS record found with name: %s and type: %s in zone ID: %s", name, recordType, zoneID)
		return nil, nil
	}

	log.Info("Found DNS record: %s (%s) with type: %s in zone ID: %s", records[0].Name, records[0].ID, records[0].Type, zoneID)
	return &records[0], nil
}
