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"
)

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

	shop := env.CreateTestShop("测试店铺", 1, nil)
	series := createPricingTestPackageSeries(t, env, "调价测试系列")
	packages := createPricingTestPackages(t, env, series.ID, 3)

	for _, pkg := range packages {
		createPricingTestAllocation(t, env, shop.ID, pkg.ID, series.ID, 5000)
	}

	t.Run("批量调价_固定金额调整", func(t *testing.T) {
		body := map[string]interface{}{
			"shop_id":   shop.ID,
			"series_id": series.ID,
			"price_adjustment": map[string]interface{}{
				"type":  "fixed",
				"value": 1000,
			},
			"change_reason": "统一调价测试",
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-package-batch-pricing", 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{})
			updatedCount := int(dataMap["updated_count"].(float64))
			assert.Equal(t, 3, updatedCount, "应更新3个套餐分配")
		}
	})

	t.Run("批量调价_百分比调整", func(t *testing.T) {
		shop2 := env.CreateTestShop("测试店铺2", 1, nil)
		series2 := createPricingTestPackageSeries(t, env, "系列2")
		packages2 := createPricingTestPackages(t, env, series2.ID, 2)

		for _, pkg := range packages2 {
			createPricingTestAllocation(t, env, shop2.ID, pkg.ID, series2.ID, 10000)
		}

		body := map[string]interface{}{
			"shop_id":   shop2.ID,
			"series_id": series2.ID,
			"price_adjustment": map[string]interface{}{
				"type":  "percent",
				"value": 100,
			},
			"change_reason": "加价10%",
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-package-batch-pricing", 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)

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			updatedCount := int(dataMap["updated_count"].(float64))
			assert.Equal(t, 2, updatedCount, "应更新2个套餐分配")
		}
	})

	t.Run("批量调价_不指定系列调整所有", func(t *testing.T) {
		shop3 := env.CreateTestShop("测试店铺3", 1, nil)
		series3a := createPricingTestPackageSeries(t, env, "系列3A")
		series3b := createPricingTestPackageSeries(t, env, "系列3B")

		pkg3a := createPricingTestPackages(t, env, series3a.ID, 1)[0]
		pkg3b := createPricingTestPackages(t, env, series3b.ID, 1)[0]

		createPricingTestAllocation(t, env, shop3.ID, pkg3a.ID, series3a.ID, 8000)
		createPricingTestAllocation(t, env, shop3.ID, pkg3b.ID, series3b.ID, 8000)

		body := map[string]interface{}{
			"shop_id": shop3.ID,
			"price_adjustment": map[string]interface{}{
				"type":  "fixed",
				"value": 500,
			},
			"change_reason": "全局调价",
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-package-batch-pricing", 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)

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			updatedCount := int(dataMap["updated_count"].(float64))
			assert.GreaterOrEqual(t, updatedCount, 2, "应更新至少2个套餐分配")
		}
	})

	t.Run("批量调价_无匹配记录应失败", func(t *testing.T) {
		shop4 := env.CreateTestShop("空店铺", 1, nil)

		body := map[string]interface{}{
			"shop_id": shop4.ID,
			"price_adjustment": map[string]interface{}{
				"type":  "fixed",
				"value": 1000,
			},
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/shop-package-batch-pricing", 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 createPricingTestPackageSeries(t *testing.T, env *integ.IntegrationTestEnv, name string) *model.PackageSeries {
	t.Helper()

	timestamp := time.Now().UnixNano()
	series := &model.PackageSeries{
		SeriesCode: fmt.Sprintf("PRICING_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
}

func createPricingTestPackages(t *testing.T, env *integ.IntegrationTestEnv, seriesID uint, count int) []*model.Package {
	t.Helper()

	packages := make([]*model.Package, 0, count)
	timestamp := time.Now().UnixNano()

	for i := 0; i < count; i++ {
		pkg := &model.Package{
			PackageCode:        fmt.Sprintf("PRICING_PKG_%d_%d", timestamp, i),
			PackageName:        fmt.Sprintf("调价测试套餐%d", i+1),
			SeriesID:           seriesID,
			PackageType:        "formal",
			DurationMonths:     1,
			Price:              9900,
			SuggestedCostPrice: 5000,
			Status:             constants.StatusEnabled,
			ShelfStatus:        1,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}

		err := env.TX.Create(pkg).Error
		require.NoError(t, err)

		packages = append(packages, pkg)
	}

	return packages
}

func createPricingTestAllocation(t *testing.T, env *integ.IntegrationTestEnv, shopID, packageID, seriesID uint, costPrice int64) *model.ShopPackageAllocation {
	t.Helper()

	allocation := &model.ShopPackageAllocation{
		ShopID:       shopID,
		PackageID:    packageID,
		AllocationID: 0,
		CostPrice:    costPrice,
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}

	err := env.TX.Create(allocation).Error
	require.NoError(t, err)

	return allocation
}
