package commerce

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strconv"
	"strings"
	"testing"
)

func TestZJMFCancelUsesImmediateHostCancelAndConfirmsDeletedState(t *testing.T) {
	t.Setenv("JWT_SECRET_KEY", "migration-completion-test-secret")
	var cancelCalls int
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		switch r.URL.Path {
		case "/zjmf_api_login":
			if r.Method != http.MethodPost {
				t.Fatalf("login method = %s", r.Method)
			}
			_ = r.ParseForm()
			if r.Form.Get("username") != "agent" || r.Form.Get("password") != "secret" {
				t.Fatalf("login form = %#v", r.Form)
			}
			_, _ = w.Write([]byte(`{"status":200,"jwt":"token"}`))
		case "/host/cancel":
			cancelCalls++
			if r.Method != http.MethodPost {
				t.Fatalf("cancel method = %s", r.Method)
			}
			if r.Header.Get("Authorization") != "Bearer token" {
				t.Fatalf("authorization = %q", r.Header.Get("Authorization"))
			}
			_ = r.ParseForm()
			if r.Form.Get("id") != "42" || r.Form.Get("type") != "Immediate" || r.Form.Get("reason") != "用户退订" {
				t.Fatalf("cancel form = %#v", r.Form)
			}
			_, _ = w.Write([]byte(`{"status":200,"msg":"success"}`))
		case "/host/header":
			if r.Method != http.MethodGet || r.URL.Query().Get("host_id") != "42" {
				t.Fatalf("header request = %s %s", r.Method, r.URL.String())
			}
			_, _ = w.Write([]byte(`{"status":200,"data":{"host_data":{"domainstatus":"Deleted"}}}`))
		default:
			http.NotFound(w, r)
		}
	}))
	defer server.Close()

	parsed, err := url.Parse(server.URL)
	if err != nil {
		t.Fatal(err)
	}
	host, portText, err := net.SplitHostPort(parsed.Host)
	if err != nil {
		t.Fatal(err)
	}
	port, _ := strconv.Atoi(portText)
	encrypted, err := EncryptStoredSecret("secret")
	if err != nil {
		t.Fatal(err)
	}
	cloudServer := CloudServer{ServerType: "zjmf_finance", Hostname: host, Port: port, Secure: false, Username: "agent", PasswordEncrypted: encrypted}
	upstreamID := int64(42)
	instance := Instance{ID: 7, UserID: 3, UpstreamID: &upstreamID}

	result, err := submitZJMFCancel(context.Background(), cloudServer, instance, "用户退订")
	if err != nil {
		t.Fatal(err)
	}
	if result.StatusCode != http.StatusOK || cancelCalls != 1 {
		t.Fatalf("cancel result = %#v, calls = %d", result, cancelCalls)
	}
	state, err := checkZJMFTermination(context.Background(), cloudServer, instance)
	if err != nil {
		t.Fatal(err)
	}
	if state.Status != "success" {
		t.Fatalf("termination state = %#v", state)
	}
}

func TestInstanceUpstreamPayloadSanitizesNestedSecrets(t *testing.T) {
	payload := map[string]any{
		"password": "top-secret",
		"host_data": map[string]any{
			"rootpassword": "root-secret",
			"mainip":       "192.0.2.10",
		},
		"items": []any{map[string]any{"new_password": "changed", "id": 1}},
	}
	got := sanitizeInstanceUpstreamPayload(payload)
	encoded, _ := json.Marshal(got)
	text := string(encoded)
	for _, secret := range []string{"top-secret", "root-secret", "changed"} {
		if strings.Contains(text, secret) {
			t.Fatalf("sanitized payload leaked %q: %s", secret, text)
		}
	}
	if !strings.Contains(text, "192.0.2.10") {
		t.Fatalf("sanitized payload lost public detail: %s", text)
	}
}

func TestServiceOrdersSortRelatedDependencies(t *testing.T) {
	makeOrder := func(id int64, itemType string) Order {
		return Order{ID: id, ItemsSnapshot: jsonRawFromAny([]map[string]any{{"type": itemType, "instance_id": 9}})}
	}
	orders := []Order{
		makeOrder(4, "disk_addon"),
		makeOrder(2, "package_upgrade"),
		makeOrder(5, "renewal"),
		makeOrder(3, "disk_resize"),
	}
	got := sortOrdersByDependency(orders)
	want := []int64{2, 3, 4, 5}
	for index, order := range got {
		if order.ID != want[index] {
			t.Fatalf("dependency order = %v, want %v", orderIDs(got), want)
		}
	}
}

func TestBusinessEmailCarriesRichTemplateAndEscapesValues(t *testing.T) {
	message := newBusinessEmailMessage(
		"commerce.test",
		"subject",
		"plain",
		"<script>alert(1)</script>",
		"lead",
		[]businessEmailRow{{Label: "实例", Value: `<img src=x onerror=alert(1)>`}},
		"note",
		"打开",
		"https://example.com/?a=1&b=2",
	)
	if message.Template != "commerce.test" || message.TextBody != "plain" || message.HTMLBody == "" {
		t.Fatalf("rich email message = %#v", message)
	}
	if strings.Contains(message.HTMLBody, "<script>") || strings.Contains(message.HTMLBody, "<img src=x") {
		t.Fatalf("HTML template did not escape values: %s", message.HTMLBody)
	}
	if !strings.Contains(message.HTMLBody, "&lt;script&gt;") || !strings.Contains(message.HTMLBody, "&lt;img") {
		t.Fatalf("HTML template missing escaped content: %s", message.HTMLBody)
	}
}

func orderIDs(orders []Order) []int64 {
	out := make([]int64, 0, len(orders))
	for _, order := range orders {
		out = append(out, order.ID)
	}
	return out
}

func Example_serviceOrderDependency() {
	fmt.Println(orderTypeRank("package_upgrade"), orderTypeRank("disk_resize"), orderTypeRank("disk_addon"))
	// Output: 0 1 2
}
