package models

// methods that make RecordConfig meet the dns.RR interface.

import (
	"fmt"
	"log"
	"strings"

	"github.com/miekg/dns"
)

//// Header Header returns the header of an resource record.
//func (rc *RecordConfig) Header() *dns.RR_Header {
//	log.Fatal("Header not implemented")
//	return nil
//}

// String returns the text representation of the resource record.
func (rc *RecordConfig) String() string {
	return rc.GetTargetCombined()
}

//// copy returns a copy of the RR
//func (rc *RecordConfig) copy() dns.RR {
//	log.Fatal("Copy not implemented")
//	return dns.TypeToRR[dns.TypeA]()
//}
//
//// len returns the length (in octets) of the uncompressed RR in wire format.
//func (rc *RecordConfig) len() int {
//	log.Fatal("len not implemented")
//	return 0
//}
//
//// pack packs an RR into wire format.
//func (rc *RecordConfig) pack([]byte, int, map[string]int, bool) (int, error) {
//	log.Fatal("pack not implemented")
//	return 0, nil
//}

// Conversions

// RRstoRCs converts []dns.RR to []RecordConfigs.
func RRstoRCs(rrs []dns.RR, origin string) Records {
	rcs := make(Records, 0, len(rrs))
	for _, r := range rrs {
		var rc RecordConfig
		rc = RRtoRC(r, origin)
		rcs = append(rcs, &rc)
	}
	return rcs
}

// RRtoRC converts dns.RR to RecordConfig
func RRtoRC(rr dns.RR, origin string) RecordConfig {
	// Convert's dns.RR into our native data type (RecordConfig).
	// Records are translated directly with no changes.
	header := rr.Header()
	rc := new(RecordConfig)
	rc.Type = dns.TypeToString[header.Rrtype]
	rc.TTL = header.Ttl
	rc.Original = rr
	rc.SetLabelFromFQDN(strings.TrimSuffix(header.Name, "."), origin)
	switch v := rr.(type) { // #rtype_variations
	case *dns.A:
		panicInvalid(rc.SetTarget(v.A.String()))
	case *dns.AAAA:
		panicInvalid(rc.SetTarget(v.AAAA.String()))
	case *dns.CAA:
		panicInvalid(rc.SetTargetCAA(v.Flag, v.Tag, v.Value))
	case *dns.CNAME:
		panicInvalid(rc.SetTarget(v.Target))
	case *dns.MX:
		panicInvalid(rc.SetTargetMX(v.Preference, v.Mx))
	case *dns.NS:
		panicInvalid(rc.SetTarget(v.Ns))
	case *dns.PTR:
		panicInvalid(rc.SetTarget(v.Ptr))
	case *dns.NAPTR:
		panicInvalid(rc.SetTargetNAPTR(v.Order, v.Preference, v.Flags, v.Service, v.Regexp, v.Replacement))
	case *dns.SOA:
		panicInvalid(rc.SetTargetSOA(v.Ns, v.Mbox, v.Serial, v.Refresh, v.Retry, v.Expire, v.Minttl))
	case *dns.SRV:
		panicInvalid(rc.SetTargetSRV(v.Priority, v.Weight, v.Port, v.Target))
	case *dns.SSHFP:
		panicInvalid(rc.SetTargetSSHFP(v.Algorithm, v.Type, v.FingerPrint))
	case *dns.TLSA:
		panicInvalid(rc.SetTargetTLSA(v.Usage, v.Selector, v.MatchingType, v.Certificate))
	case *dns.TXT:
		panicInvalid(rc.SetTargetTXTs(v.Txt))
	default:
		log.Fatalf("rrToRecord: Unimplemented zone record type=%s (%v)\n", rc.Type, rr)
	}
	return *rc
}

func panicInvalid(err error) {
	if err != nil {
		panic(fmt.Errorf("unparsable record received from BIND: %w", err))
	}
}
