package test

import (
	"testing"

	"github.com/coredns/coredns/plugin/pkg/dnstest"

	"github.com/miekg/dns"
)

// TestSIITAfterForward is a regression test for the plugin.cfg ordering bug:
// siit must run AFTER forward in the plugin chain so it can see (and rewrite)
// the AAAA answer forward returns, rather than running before it and never
// seeing the final response.
//
// Unlike the unit tests in plugin/siit, which instantiate SIIT directly and
// wire d.Next/d.Upstream to fakes, this test drives the real plugin chain
// built from plugin.cfg via a Corefile, so a future ordering regression
// (siit placed after cache/forward again) will fail here even though it
// can't be detected by the package-level unit tests.
func TestSIITAfterForward(t *testing.T) {
	// Upstream "authoritative" server: NODATA for A, a mapped AAAA for AAAA.
	upstream := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
		m := new(dns.Msg)
		m.SetReply(r)

		switch r.Question[0].Qtype {
		case dns.TypeA:
			// NODATA: success, no answer section -- this is what makes
			// siit's responseShouldSIIT return true.
		case dns.TypeAAAA:
			rr, err := dns.NewRR("example.org. 60 IN AAAA 64:ff9b::192.0.2.42")
			if err != nil {
				t.Fatalf("failed to build AAAA record: %v", err)
			}
			m.Answer = []dns.RR{rr}
		}

		w.WriteMsg(m)
	})
	defer upstream.Close()

	corefile := `example.org:0 {
		siit {
			ipv6_prefix 64:ff9b::/96
		}
		forward . ` + upstream.Addr + `
	}`

	server, udp, _, err := CoreDNSServerAndPorts(corefile)
	if err != nil {
		t.Fatalf("could not start CoreDNS test server: %v", err)
	}
	defer server.Stop()

	m := new(dns.Msg)
	m.SetQuestion("example.org.", dns.TypeA)

	resp, err := dns.Exchange(m, udp)
	if err != nil {
		t.Fatalf("query failed: %v", err)
	}

	if resp.Rcode != dns.RcodeSuccess {
		t.Fatalf("expected RcodeSuccess, got %s", dns.RcodeToString[resp.Rcode])
	}
	if len(resp.Answer) != 1 {
		t.Fatalf("expected 1 answer record, got %d: %v", len(resp.Answer), resp.Answer)
	}

	a, ok := resp.Answer[0].(*dns.A)
	if !ok {
		t.Fatalf("expected an A record in the answer, got %T: %v", resp.Answer[0], resp.Answer[0])
	}

	want := "192.0.2.42"
	if a.A.String() != want {
		t.Errorf("expected synthesized A record %s, got %s -- if this is empty/unset, siit likely ran before forward in the plugin chain and never saw the upstream's AAAA answer", want, a.A.String())
	}
}
