package gateway

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func TestNewClient(t *testing.T) {
	client := NewClient("https://test.example.com", "testAppID", "testSecret")

	if client.baseURL != "https://test.example.com" {
		t.Errorf("baseURL = %s, want https://test.example.com", client.baseURL)
	}
	if client.appID != "testAppID" {
		t.Errorf("appID = %s, want testAppID", client.appID)
	}
	if client.appSecret != "testSecret" {
		t.Errorf("appSecret = %s, want testSecret", client.appSecret)
	}
	if client.timeout != 30*time.Second {
		t.Errorf("timeout = %v, want 30s", client.timeout)
	}
	if client.httpClient == nil {
		t.Error("httpClient should not be nil")
	}
}

func TestWithTimeout(t *testing.T) {
	client := NewClient("https://test.example.com", "testAppID", "testSecret").
		WithTimeout(60 * time.Second)

	if client.timeout != 60*time.Second {
		t.Errorf("timeout = %v, want 60s", client.timeout)
	}
}

func TestWithTimeout_Chain(t *testing.T) {
	// 验证链式调用返回同一个 Client 实例
	client := NewClient("https://test.example.com", "testAppID", "testSecret")
	returned := client.WithTimeout(45 * time.Second)

	if returned != client {
		t.Error("WithTimeout should return the same Client instance for chaining")
	}
}

func TestDoRequest_Success(t *testing.T) {
	// 创建 mock HTTP 服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 验证请求方法
		if r.Method != http.MethodPost {
			t.Errorf("Method = %s, want POST", r.Method)
		}

		// 验证 Content-Type
		if r.Header.Get("Content-Type") != "application/json;charset=utf-8" {
			t.Errorf("Content-Type = %s, want application/json;charset=utf-8", r.Header.Get("Content-Type"))
		}

		// 验证请求体格式
		var reqBody map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
			t.Fatalf("解析请求体失败: %v", err)
		}

		// 验证必需字段
		if _, ok := reqBody["appId"]; !ok {
			t.Error("请求体缺少 appId 字段")
		}
		if _, ok := reqBody["data"]; !ok {
			t.Error("请求体缺少 data 字段")
		}
		if _, ok := reqBody["sign"]; !ok {
			t.Error("请求体缺少 sign 字段")
		}
		if _, ok := reqBody["timestamp"]; !ok {
			t.Error("请求体缺少 timestamp 字段")
		}

		// 返回 mock 响应
		resp := GatewayResponse{
			Code:    200,
			Msg:     "成功",
			Data:    json.RawMessage(`{"test":"data"}`),
			TraceID: "test-trace-id",
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(resp)
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	ctx := context.Background()
	businessData := map[string]interface{}{
		"params": map[string]string{
			"cardNo": "898608070422D0010269",
		},
	}

	data, err := client.doRequest(ctx, "/test", businessData)
	if err != nil {
		t.Fatalf("doRequest() error = %v", err)
	}

	if string(data) != `{"test":"data"}` {
		t.Errorf("data = %s, want {\"test\":\"data\"}", string(data))
	}
}

func TestDoRequest_BusinessError(t *testing.T) {
	// 创建返回业务错误的 mock 服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		resp := GatewayResponse{
			Code:    500,
			Msg:     "业务处理失败",
			Data:    nil,
			TraceID: "error-trace-id",
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(resp)
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	ctx := context.Background()
	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected business error")
	}

	// 验证错误信息包含业务错误内容
	if !strings.Contains(err.Error(), "业务错误") {
		t.Errorf("error should contain '业务错误', got: %v", err)
	}
}

func TestDoRequest_Timeout(t *testing.T) {
	// 创建延迟响应的服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(500 * time.Millisecond) // 延迟 500ms
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret").
		WithTimeout(100 * time.Millisecond) // 设置 100ms 超时

	ctx := context.Background()
	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected timeout error")
	}

	// 验证是超时错误
	if !strings.Contains(err.Error(), "超时") {
		t.Errorf("error should contain '超时', got: %v", err)
	}
}

func TestDoRequest_HTTPStatusError(t *testing.T) {
	// 创建返回 500 状态码的服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Internal Server Error"))
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	ctx := context.Background()
	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected HTTP status error")
	}

	// 验证错误信息包含 HTTP 状态码
	if !strings.Contains(err.Error(), "500") {
		t.Errorf("error should contain '500', got: %v", err)
	}
}

func TestDoRequest_InvalidResponse(t *testing.T) {
	// 创建返回无效 JSON 的服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte("invalid json"))
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	ctx := context.Background()
	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected JSON parse error")
	}

	// 验证错误信息包含解析失败提示
	if !strings.Contains(err.Error(), "解析") {
		t.Errorf("error should contain '解析', got: %v", err)
	}
}

func TestDoRequest_ContextCanceled(t *testing.T) {
	// 创建正常响应的服务器（但会延迟）
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(500 * time.Millisecond)
		resp := GatewayResponse{Code: 200, Msg: "成功"}
		json.NewEncoder(w).Encode(resp)
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	// 创建已取消的 context
	ctx, cancel := context.WithCancel(context.Background())
	cancel() // 立即取消

	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected context canceled error")
	}
}

func TestDoRequest_NetworkError(t *testing.T) {
	// 使用无效的服务器地址
	client := NewClient("http://127.0.0.1:1", "testAppID", "testSecret").
		WithTimeout(1 * time.Second)

	ctx := context.Background()
	_, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err == nil {
		t.Fatal("doRequest() expected network error")
	}
}

func TestDoRequest_EmptyBusinessData(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		resp := GatewayResponse{
			Code: 200,
			Msg:  "成功",
			Data: json.RawMessage(`{}`),
		}
		json.NewEncoder(w).Encode(resp)
	}))
	defer server.Close()

	client := NewClient(server.URL, "testAppID", "testSecret")

	ctx := context.Background()
	data, err := client.doRequest(ctx, "/test", map[string]interface{}{})
	if err != nil {
		t.Fatalf("doRequest() error = %v", err)
	}

	if string(data) != `{}` {
		t.Errorf("data = %s, want {}", string(data))
	}
}

func TestIntegration_QueryCardStatus(t *testing.T) {
	if testing.Short() {
		t.Skip("跳过集成测试")
	}

	baseURL := "https://lplan.whjhft.com/openapi"
	appID := "60bgt1X8i7AvXqkd"
	appSecret := "BZeQttaZQt0i73moF"

	client := NewClient(baseURL, appID, appSecret).WithTimeout(30 * time.Second)
	ctx := context.Background()

	resp, err := client.QueryCardStatus(ctx, &CardStatusReq{
		CardNo: "898608070422D0010269",
	})

	if err != nil {
		t.Fatalf("QueryCardStatus() error = %v", err)
	}

	if resp.ICCID == "" {
		t.Error("ICCID should not be empty")
	}
	if resp.CardStatus == "" {
		t.Error("CardStatus should not be empty")
	}

	t.Logf("Integration test passed: ICCID=%s, Status=%s", resp.ICCID, resp.CardStatus)
}

func TestIntegration_QueryFlow(t *testing.T) {
	if testing.Short() {
		t.Skip("跳过集成测试")
	}

	baseURL := "https://lplan.whjhft.com/openapi"
	appID := "60bgt1X8i7AvXqkd"
	appSecret := "BZeQttaZQt0i73moF"

	client := NewClient(baseURL, appID, appSecret).WithTimeout(30 * time.Second)
	ctx := context.Background()

	resp, err := client.QueryFlow(ctx, &FlowQueryReq{
		CardNo: "898608070422D0010269",
	})

	if err != nil {
		t.Fatalf("QueryFlow() error = %v", err)
	}

	if resp.UsedFlow < 0 {
		t.Error("UsedFlow should not be negative")
	}

	t.Logf("Integration test passed: UsedFlow=%d %s", resp.UsedFlow, resp.Unit)
}
