package doh

import (
	"context"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCheckDnsPropagation_AllCases(t *testing.T) {
	// Backup original endpoints and restore after test
	originalEndpoints := dohEndpoints
	defer func() { dohEndpoints = originalEndpoints }()

	tests := []struct {
		name         string
		handler      func(w http.ResponseWriter, r *http.Request)
		expectedBool bool
		expectedMsg  string
	}{
		{
			name: "Success_BothProvidersReturnValidIP",
			handler: func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusOK)
				_, _ = w.Write([]byte(`{"Status": 0, "Answer": [{"data": "1.2.3.4"}]}`))
			},
			expectedBool: true,
			expectedMsg:  "",
		},
		{
			name: "Unreachable_BothProvidersReturnStatus3",
			handler: func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusOK)
				_, _ = w.Write([]byte(`{"Status": 3}`))
			},
			expectedBool: false,
			expectedMsg:  MsgDnsNotReachable,
		},
		{
			name: "Unreachable_Status0WithEmptyAnswer",
			handler: func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusOK)
				_, _ = w.Write([]byte(`{"Status": 0, "Answer": []}`))
			},
			expectedBool: false,
			expectedMsg:  MsgDnsNotReachable,
		},
		{
			name: "Resilience_GoogleFailsButCloudflareSucceeds",
			handler: func(w http.ResponseWriter, r *http.Request) {
				if strings.Contains(r.URL.RawQuery, "google") {
					w.WriteHeader(http.StatusInternalServerError)
				} else {
					w.WriteHeader(http.StatusOK)
					_, _ = w.Write([]byte(`{"Status": 0, "Answer": [{"data": "1.2.3.4"}]}`))
				}
			},
			expectedBool: true,
			expectedMsg:  "",
		},
		{
			name: "Failure_AllProvidersReturn500",
			handler: func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusInternalServerError)
			},
			expectedBool: false,
			expectedMsg:  MsgDnsProbeFailed,
		},
		{
			name: "Failure_InvalidJSONResponse",
			handler: func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusOK)
				_, _ = w.Write([]byte(`{broken-json`))
			},
			expectedBool: false,
			expectedMsg:  MsgDnsProbeFailed,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			server := httptest.NewServer(http.HandlerFunc(tt.handler))
			defer server.Close()

			// Inject mock server URL into the endpoints
			dohEndpoints = map[string]string{
				"google":     server.URL + "?provider=google&name=%s",
				"cloudflare": server.URL + "?provider=cloudflare&name=%s",
			}

			reachable, msg := CheckDnsPropagation(context.Background(), "test-dns.com")

			assert.Equal(t, tt.expectedBool, reachable)
			assert.Equal(t, tt.expectedMsg, msg)
		})
	}
}

func TestFetchDoh_EdgeCases(t *testing.T) {
	// Test specific internal error logic for fetchDoh
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(`{"Status": 5}`)) // Status 5 = Refused
	}))
	defer ts.Close()

	reachable, msg, err := fetchDoh(context.Background(), ts.URL)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "dns status 5")
	assert.False(t, reachable)
	assert.Empty(t, msg)
}

func TestCheckDnsPropagation_RealWorld(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping real-world test in short mode")
	}

	tests := []struct {
		name         string
		dns          string
		expectedBool bool
		expectedMsg  string
	}{
		{
			name:         "RealWorld_KnownDomain_ShouldBeReachable",
			dns:          "www.baidu.com",
			expectedBool: true,
			expectedMsg:  "",
		},
		{
			name:         "RealWorld_NonExistentDomain_ShouldBeUnreachable",
			dns:          "this-domain-should-never-exist-12345.invalid",
			expectedBool: false,
			expectedMsg:  MsgDnsNotReachable,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			reachable, msg := CheckDnsPropagation(context.Background(), tt.dns)

			assert.Equal(t, tt.expectedBool, reachable, "Failed for domain: "+tt.dns)
			assert.Equal(t, tt.expectedMsg, msg)
		})
	}
}
