package package_series

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestPackageSeriesService_Create(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	t.Run("创建成功", func(t *testing.T) {
		seriesCode := fmt.Sprintf("SVC_CREATE_%d", time.Now().UnixNano())
		req := &dto.CreatePackageSeriesRequest{
			SeriesCode:  seriesCode,
			SeriesName:  "测试套餐系列",
			Description: "服务层测试",
		}

		resp, err := svc.Create(ctx, req)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
		assert.Equal(t, req.SeriesCode, resp.SeriesCode)
		assert.Equal(t, req.SeriesName, resp.SeriesName)
		assert.Equal(t, constants.StatusEnabled, resp.Status)
	})

	t.Run("编码重复失败", func(t *testing.T) {
		seriesCode := fmt.Sprintf("SVC_DUP_%d", time.Now().UnixNano())
		req1 := &dto.CreatePackageSeriesRequest{
			SeriesCode:  seriesCode,
			SeriesName:  "第一个系列",
			Description: "测试重复",
		}

		_, err := svc.Create(ctx, req1)
		require.NoError(t, err)

		req2 := &dto.CreatePackageSeriesRequest{
			SeriesCode:  seriesCode,
			SeriesName:  "第二个系列",
			Description: "重复编码",
		}

		_, err = svc.Create(ctx, req2)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeConflict, appErr.Code)
	})

	t.Run("未授权失败", func(t *testing.T) {
		req := &dto.CreatePackageSeriesRequest{
			SeriesCode:  fmt.Sprintf("SVC_UNAUTH_%d", time.Now().UnixNano()),
			SeriesName:  "未授权测试",
			Description: "无用户上下文",
		}

		_, err := svc.Create(context.Background(), req)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
	})
}

func TestPackageSeriesService_Get(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	seriesCode := fmt.Sprintf("SVC_GET_%d", time.Now().UnixNano())
	req := &dto.CreatePackageSeriesRequest{
		SeriesCode:  seriesCode,
		SeriesName:  "查询测试",
		Description: "用于查询测试",
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("获取存在的系列", func(t *testing.T) {
		resp, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, created.SeriesCode, resp.SeriesCode)
		assert.Equal(t, created.SeriesName, resp.SeriesName)
	})

	t.Run("获取不存在的系列", func(t *testing.T) {
		_, err := svc.Get(ctx, 99999)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestPackageSeriesService_Update(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	seriesCode := fmt.Sprintf("SVC_UPD_%d", time.Now().UnixNano())
	req := &dto.CreatePackageSeriesRequest{
		SeriesCode:  seriesCode,
		SeriesName:  "更新测试",
		Description: "原始描述",
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("更新成功", func(t *testing.T) {
		newName := "更新后的名称"
		newDesc := "更新后的描述"
		updateReq := &dto.UpdatePackageSeriesRequest{
			SeriesName:  &newName,
			Description: &newDesc,
		}

		resp, err := svc.Update(ctx, created.ID, updateReq)
		require.NoError(t, err)
		assert.Equal(t, newName, resp.SeriesName)
		assert.Equal(t, newDesc, resp.Description)
	})

	t.Run("更新不存在的系列", func(t *testing.T) {
		newName := "test"
		updateReq := &dto.UpdatePackageSeriesRequest{
			SeriesName: &newName,
		}

		_, err := svc.Update(ctx, 99999, updateReq)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestPackageSeriesService_Delete(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	seriesCode := fmt.Sprintf("SVC_DEL_%d", time.Now().UnixNano())
	req := &dto.CreatePackageSeriesRequest{
		SeriesCode:  seriesCode,
		SeriesName:  "删除测试",
		Description: "用于删除测试",
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("删除成功", func(t *testing.T) {
		err := svc.Delete(ctx, created.ID)
		require.NoError(t, err)

		_, err = svc.Get(ctx, created.ID)
		require.Error(t, err)
	})

	t.Run("删除不存在的系列", func(t *testing.T) {
		err := svc.Delete(ctx, 99999)
		require.Error(t, err)
	})
}

func TestPackageSeriesService_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	seriesList := []dto.CreatePackageSeriesRequest{
		{
			SeriesCode:  fmt.Sprintf("SVC_LIST_001_%d", time.Now().UnixNano()),
			SeriesName:  "基础套餐",
			Description: "列表测试1",
		},
		{
			SeriesCode:  fmt.Sprintf("SVC_LIST_002_%d", time.Now().UnixNano()),
			SeriesName:  "高级套餐",
			Description: "列表测试2",
		},
		{
			SeriesCode:  fmt.Sprintf("SVC_LIST_003_%d", time.Now().UnixNano()),
			SeriesName:  "企业套餐",
			Description: "列表测试3",
		},
	}
	for _, s := range seriesList {
		_, err := svc.Create(ctx, &s)
		require.NoError(t, err)
	}

	t.Run("查询列表", func(t *testing.T) {
		req := &dto.PackageSeriesListRequest{
			Page:     1,
			PageSize: 20,
		}
		result, total, err := svc.List(ctx, req)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(3))
		assert.GreaterOrEqual(t, len(result), 3)
	})

	t.Run("按状态过滤", func(t *testing.T) {
		status := constants.StatusEnabled
		req := &dto.PackageSeriesListRequest{
			Page:     1,
			PageSize: 20,
			Status:   &status,
		}
		result, total, err := svc.List(ctx, req)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(3))
		for _, s := range result {
			assert.Equal(t, constants.StatusEnabled, s.Status)
		}
	})

	t.Run("按名称模糊搜索", func(t *testing.T) {
		seriesName := "高级"
		req := &dto.PackageSeriesListRequest{
			Page:       1,
			PageSize:   20,
			SeriesName: &seriesName,
		}
		result, total, err := svc.List(ctx, req)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(1))
		assert.GreaterOrEqual(t, len(result), 1)
	})
}

func TestPackageSeriesService_UpdateStatus(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	store := postgres.NewPackageSeriesStore(tx)
	svc := New(store)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	seriesCode := fmt.Sprintf("SVC_STATUS_%d", time.Now().UnixNano())
	req := &dto.CreatePackageSeriesRequest{
		SeriesCode:  seriesCode,
		SeriesName:  "状态测试",
		Description: "用于状态更新测试",
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)
	assert.Equal(t, constants.StatusEnabled, created.Status)

	t.Run("禁用系列", func(t *testing.T) {
		err := svc.UpdateStatus(ctx, created.ID, constants.StatusDisabled)
		require.NoError(t, err)

		updated, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, updated.Status)
	})

	t.Run("启用系列", func(t *testing.T) {
		err := svc.UpdateStatus(ctx, created.ID, constants.StatusEnabled)
		require.NoError(t, err)

		updated, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusEnabled, updated.Status)
	})

	t.Run("更新不存在的系列状态", func(t *testing.T) {
		err := svc.UpdateStatus(ctx, 99999, constants.StatusDisabled)
		require.Error(t, err)
	})
}
