package integration

import (
	"encoding/json"
	"fmt"
	"testing"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/response"
	"github.com/break/junhong_cmp_fiber/tests/testutils/integ"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// ==================== 套餐系列分配 API 测试 ====================

func TestShopSeriesAllocationAPI_Create(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("一级店铺", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")

	t.Run("平台为一级店铺分配套餐系列", func(t *testing.T) {
		body := map[string]interface{}{
			"shop_id":   shop.ID,
			"series_id": series.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 1000,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			assert.Equal(t, float64(shop.ID), dataMap["shop_id"])
			assert.Equal(t, float64(series.ID), dataMap["series_id"])
			if baseComm, ok := dataMap["base_commission"].(map[string]interface{}); ok {
				assert.Equal(t, "fixed", baseComm["mode"])
				assert.Equal(t, float64(1000), baseComm["value"])
			}
			t.Logf("创建的分配 ID: %v", dataMap["id"])
		}
	})

	t.Run("一级店铺为二级店铺分配套餐系列", func(t *testing.T) {
		parentShop := env.CreateTestShop("另一个一级店铺", 1, nil)
		childShop := env.CreateTestShop("二级店铺", 2, &parentShop.ID)
		agentAccount := env.CreateTestAccount("agent_create", "password123", constants.UserTypeAgent, &parentShop.ID, nil)
		series2 := createTestPackageSeries(t, env, "系列2")
		createTestAllocation(t, env, parentShop.ID, series2.ID, 0)

		body := map[string]interface{}{
			"shop_id":   childShop.ID,
			"series_id": series2.ID,
			"base_commission": map[string]interface{}{
				"mode":  "percent",
				"value": 100,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)
	})

	t.Run("平台不能为二级店铺分配", func(t *testing.T) {
		parent := env.CreateTestShop("父店铺", 1, nil)
		child := env.CreateTestShop("子店铺", 2, &parent.ID)
		series3 := createTestPackageSeries(t, env, "系列3")
		body := map[string]interface{}{
			"shop_id":   child.ID,
			"series_id": series3.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 500,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code, "平台不能为二级店铺分配")
	})

	t.Run("重复分配应失败", func(t *testing.T) {
		newShop := env.CreateTestShop("新店铺", 1, nil)
		series4 := createTestPackageSeries(t, env, "系列4")
		createTestAllocation(t, env, newShop.ID, series4.ID, 0)

		body := map[string]interface{}{
			"shop_id":   newShop.ID,
			"series_id": series4.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 1000,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code, "重复分配应返回错误")
	})
}

func TestShopSeriesAllocationAPI_Get(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("一级店铺", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")
	allocation := createTestAllocation(t, env, shop.ID, series.ID, 0)

	t.Run("获取分配详情", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("GET", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		dataMap := result.Data.(map[string]interface{})
		assert.Equal(t, float64(allocation.ID), dataMap["id"])
		assert.Equal(t, float64(shop.ID), dataMap["shop_id"])
	})

	t.Run("获取不存在的分配", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/shop-series-allocations/999999", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code, "应返回错误码")
	})
}

func TestShopSeriesAllocationAPI_Update(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("一级店铺", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")
	allocation := createTestAllocation(t, env, shop.ID, series.ID, 0)

	t.Run("更新基础佣金", func(t *testing.T) {
		body := map[string]interface{}{
			"base_commission": map[string]interface{}{
				"mode":  "percent",
				"value": 150,
			},
		}
		jsonBody, _ := json.Marshal(body)

		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("PUT", url, jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		dataMap := result.Data.(map[string]interface{})
		if baseComm, ok := dataMap["base_commission"].(map[string]interface{}); ok {
			assert.Equal(t, "percent", baseComm["mode"])
			assert.Equal(t, float64(150), baseComm["value"])
		}
	})

	t.Run("启用梯度佣金", func(t *testing.T) {
		enableTier := true
		body := map[string]interface{}{
			"enable_tier_commission": &enableTier,
		}
		jsonBody, _ := json.Marshal(body)

		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("PUT", url, jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)
	})
}

func TestShopSeriesAllocationAPI_Delete(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("一级店铺", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")
	allocation := createTestAllocation(t, env, shop.ID, series.ID, 0)

	t.Run("删除分配", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("DELETE", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		getResp, err := env.AsSuperAdmin().Request("GET", url, nil)
		require.NoError(t, err)
		defer getResp.Body.Close()

		var getResult response.Response
		json.NewDecoder(getResp.Body).Decode(&getResult)
		assert.NotEqual(t, 0, getResult.Code, "删除后应无法获取")
	})
}

func TestShopSeriesAllocationAPI_List(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop1 := env.CreateTestShop("店铺1", 1, nil)
	shop2 := env.CreateTestShop("店铺2", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")
	createTestAllocation(t, env, shop1.ID, series.ID, 0)
	createTestAllocation(t, env, shop2.ID, series.ID, 0)

	t.Run("获取分配列表", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/shop-series-allocations?page=1&page_size=20", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)
	})

	t.Run("按店铺ID筛选", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/shop-series-allocations?shop_id=%d", shop1.ID)
		resp, err := env.AsSuperAdmin().Request("GET", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)
	})

	t.Run("按系列ID筛选", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/shop-series-allocations?series_id=%d", series.ID)
		resp, err := env.AsSuperAdmin().Request("GET", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)
	})
}

func TestShopSeriesAllocationAPI_UpdateStatus(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("一级店铺", 1, nil)
	series := createTestPackageSeries(t, env, "测试系列")
	allocation := createTestAllocation(t, env, shop.ID, series.ID, 0)

	t.Run("禁用分配", func(t *testing.T) {
		body := map[string]interface{}{
			"status": constants.StatusDisabled,
		}
		jsonBody, _ := json.Marshal(body)

		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d/status", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("PUT", url, jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		getURL := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		getResp, _ := env.AsSuperAdmin().Request("GET", getURL, nil)
		defer getResp.Body.Close()

		var getResult response.Response
		json.NewDecoder(getResp.Body).Decode(&getResult)
		dataMap := getResult.Data.(map[string]interface{})
		assert.Equal(t, float64(constants.StatusDisabled), dataMap["status"])
	})

	t.Run("启用分配", func(t *testing.T) {
		body := map[string]interface{}{
			"status": constants.StatusEnabled,
		}
		jsonBody, _ := json.Marshal(body)

		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d/status", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("PUT", url, jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)
	})
}

// ==================== 一次性佣金配置测试 ====================

func TestShopSeriesAllocationAPI_OneTimeCommission(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	t.Run("创建分配-固定类型一次性佣金配置落库", func(t *testing.T) {
		shop := env.CreateTestShop("一次性佣金测试店铺1", 1, nil)
		series := createTestPackageSeries(t, env, "一次性佣金测试系列1")

		body := map[string]interface{}{
			"shop_id":   shop.ID,
			"series_id": series.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 1000,
			},
			"enable_one_time_commission": true,
			"one_time_commission_config": map[string]interface{}{
				"type":      "fixed",
				"trigger":   "accumulated_recharge",
				"threshold": 10000,
				"mode":      "fixed",
				"value":     500,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)

		dataMap := result.Data.(map[string]interface{})
		assert.Equal(t, true, dataMap["enable_one_time_commission"])
		if cfg, ok := dataMap["one_time_commission_config"].(map[string]interface{}); ok {
			assert.Equal(t, "fixed", cfg["type"])
			assert.Equal(t, "accumulated_recharge", cfg["trigger"])
			assert.Equal(t, float64(10000), cfg["threshold"])
			assert.Equal(t, "fixed", cfg["mode"])
			assert.Equal(t, float64(500), cfg["value"])
		} else {
			t.Error("一次性佣金配置应返回")
		}
	})

	t.Run("创建分配-梯度类型一次性佣金配置落库", func(t *testing.T) {
		shop := env.CreateTestShop("一次性佣金测试店铺2", 1, nil)
		series := createTestPackageSeries(t, env, "一次性佣金测试系列2")

		body := map[string]interface{}{
			"shop_id":   shop.ID,
			"series_id": series.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 1000,
			},
			"enable_one_time_commission": true,
			"one_time_commission_config": map[string]interface{}{
				"type":      "tiered",
				"trigger":   "single_recharge",
				"threshold": 5000,
				"tiers": []map[string]interface{}{
					{"tier_type": "sales_count", "threshold": 10, "mode": "fixed", "value": 100},
					{"tier_type": "sales_count", "threshold": 50, "mode": "fixed", "value": 500},
					{"tier_type": "sales_amount", "threshold": 100000, "mode": "percent", "value": 50},
				},
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code, "应返回成功: %s", result.Message)

		dataMap := result.Data.(map[string]interface{})
		assert.Equal(t, true, dataMap["enable_one_time_commission"])
		if cfg, ok := dataMap["one_time_commission_config"].(map[string]interface{}); ok {
			assert.Equal(t, "tiered", cfg["type"])
			assert.Equal(t, "single_recharge", cfg["trigger"])
			if tiers, ok := cfg["tiers"].([]interface{}); ok {
				assert.Equal(t, 3, len(tiers), "应有3个梯度档位")
			} else {
				t.Error("梯度档位应返回")
			}
		}
	})

	t.Run("创建分配-启用一次性佣金但未提供配置应失败", func(t *testing.T) {
		shop := env.CreateTestShop("一次性佣金测试店铺3", 1, nil)
		series := createTestPackageSeries(t, env, "一次性佣金测试系列3")

		body := map[string]interface{}{
			"shop_id":   shop.ID,
			"series_id": series.ID,
			"base_commission": map[string]interface{}{
				"mode":  "fixed",
				"value": 1000,
			},
			"enable_one_time_commission": true,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-series-allocations", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code, "启用一次性佣金但未提供配置应失败")
	})

	t.Run("更新分配-更新一次性佣金配置", func(t *testing.T) {
		shop := env.CreateTestShop("一次性佣金测试店铺4", 1, nil)
		series := createTestPackageSeries(t, env, "一次性佣金测试系列4")
		allocation := createTestAllocation(t, env, shop.ID, series.ID, 0)

		enableOneTime := true
		body := map[string]interface{}{
			"enable_one_time_commission": &enableOneTime,
			"one_time_commission_config": map[string]interface{}{
				"type":      "fixed",
				"trigger":   "accumulated_recharge",
				"threshold": 20000,
				"mode":      "percent",
				"value":     100,
			},
		}
		jsonBody, _ := json.Marshal(body)

		url := fmt.Sprintf("/api/admin/shop-series-allocations/%d", allocation.ID)
		resp, err := env.AsSuperAdmin().Request("PUT", url, jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code, "更新应成功: %s", result.Message)

		dataMap := result.Data.(map[string]interface{})
		assert.Equal(t, true, dataMap["enable_one_time_commission"])
		if cfg, ok := dataMap["one_time_commission_config"].(map[string]interface{}); ok {
			assert.Equal(t, float64(20000), cfg["threshold"])
			assert.Equal(t, "percent", cfg["mode"])
			assert.Equal(t, float64(100), cfg["value"])
		}
	})
}

// ==================== 梯度佣金 API 测试 ====================

// ==================== 权限测试 ====================

func TestShopSeriesAllocationAPI_Auth(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	t.Run("未认证请求应返回错误", func(t *testing.T) {
		resp, err := env.ClearAuth().Request("GET", "/api/admin/shop-series-allocations", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code, "未认证请求应返回错误码")
	})
}

// ==================== 辅助函数 ====================

// createTestPackageSeries 创建测试套餐系列
func createTestPackageSeries(t *testing.T, env *integ.IntegrationTestEnv, name string) *model.PackageSeries {
	t.Helper()

	timestamp := time.Now().UnixNano()
	series := &model.PackageSeries{
		SeriesCode: fmt.Sprintf("SERIES_%d", timestamp),
		SeriesName: name,
		Status:     constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}

	err := env.TX.Create(series).Error
	require.NoError(t, err, "创建测试套餐系列失败")

	return series
}

// createTestAllocation 创建测试分配
func createTestAllocation(t *testing.T, env *integ.IntegrationTestEnv, shopID, seriesID, allocatorShopID uint) *model.ShopSeriesAllocation {
	t.Helper()

	allocation := &model.ShopSeriesAllocation{
		ShopID:              shopID,
		SeriesID:            seriesID,
		AllocatorShopID:     allocatorShopID,
		BaseCommissionMode:  "fixed",
		BaseCommissionValue: 1000,
		Status:              constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}

	err := env.TX.Create(allocation).Error
	require.NoError(t, err, "创建测试分配失败")

	return allocation
}
