package regfishapi

import "context"

// ZoneSOA holds the SOA parameters of a zone.
type ZoneSOA struct {
	PrimaryNameserver string `json:"primary_nameserver"`
	Mailbox           string `json:"mailbox"`
	Serial            int64  `json:"serial"`
	Refresh           int    `json:"refresh"`
	Retry             int    `json:"retry"`
	Expire            int    `json:"expire"`
	Minimum           int    `json:"minimum"`
	TTL               int    `json:"ttl"`
}

// ZoneDelegationNameserver is one of the nameservers a zone is delegated to.
type ZoneDelegationNameserver struct {
	Host string  `json:"host"`
	IPv4 *string `json:"ipv4"`
}

// ZoneSummary describes a DNS zone without its records.
type ZoneSummary struct {
	Domain string `json:"domain"`
	Origin string `json:"origin"`
	Active bool   `json:"active"`
	// Signed reports whether the regfish-hosted zone itself is signed.
	Signed bool `json:"signed"`
	// UsingRegfishNameservers reports whether the domain currently uses
	// regfish authoritative nameservers.
	UsingRegfishNameservers bool                       `json:"using_regfish_nameservers"`
	DelegationNameservers   []ZoneDelegationNameserver `json:"delegation_nameservers"`
	SOA                     ZoneSOA                    `json:"soa"`
	RecordCount             int                        `json:"record_count"`
	// DNSSECState is the high-level status: "active", "pending" or "inactive".
	DNSSECState string `json:"dnssec_state"`
}

// ZoneCounts breaks down the records of a zone.
type ZoneCounts struct {
	RecordsTotal  int            `json:"records_total"`
	RecordsActive int            `json:"records_active"`
	RecordsAuto   int            `json:"records_auto"`
	RecordsManual int            `json:"records_manual"`
	ByType        map[string]int `json:"by_type"`
}

// ZoneRecord is the superset record representation returned by the detailed
// zone endpoint. Unlike ListRecordsByDomain this includes NS records.
type ZoneRecord struct {
	ID int `json:"id"`
	// Name is "@" for apex records and fully qualified otherwise.
	Name       string `json:"name"`
	Type       string `json:"type"`
	Data       string `json:"data"`
	Priority   *int   `json:"priority,omitempty"`
	Flags      *int   `json:"flags,omitempty"`
	Tag        string `json:"tag,omitempty"`
	TTL        int    `json:"ttl"`
	Auto       bool   `json:"auto"`
	Active     bool   `json:"active"`
	Annotation string `json:"annotation,omitempty"`
	TSCreated  int64  `json:"ts_created"`
	TSUpdated  int64  `json:"ts_updated"`
}

// ZoneDetail is a zone including its DNSSEC state and all of its records.
type ZoneDetail struct {
	ZoneSummary
	DNSSEC  DNSSEC       `json:"dnssec"`
	Counts  ZoneCounts   `json:"counts"`
	Records []ZoneRecord `json:"records"`
}

// ListDNSZones lists the DNS zones of the account with SOA data, delegated
// nameservers, DNSSEC status and record counts.
func (c *Client) ListDNSZones(ctx context.Context) ([]ZoneSummary, error) {
	var out []ZoneSummary
	err := c.doJSON(ctx, "GET", "/dns/zones", nil, &out)
	return out, err
}

// GetDNSZoneByDomain retrieves the complete DNS zone of a domain, including
// all records and NS entries.
func (c *Client) GetDNSZoneByDomain(ctx context.Context, domain string) (ZoneDetail, error) {
	var out ZoneDetail
	err := c.doJSON(ctx, "GET", "/dns/zones/"+pathSegment(domain), nil, &out)
	return out, err
}

// ExportDNSZoneBindByDomain exports the zone as a BIND-compatible zone file.
// Non-standard ALIAS records are included as comments and, where possible, as
// resolved A records.
func (c *Client) ExportDNSZoneBindByDomain(ctx context.Context, domain string) ([]byte, error) {
	res, err := c.doRaw(ctx, "GET", "/dns/zones/"+pathSegment(domain)+"/export", nil, nil)
	if err != nil {
		return nil, err
	}
	return res.Body, nil
}
