package integration

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

	"github.com/gofiber/fiber/v2"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"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"
)

// TestAccountPermission_12_2 企业账号访问账号管理接口被路由层拦截
func TestAccountPermission_12_2(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("测试店铺", 1, nil)
	enterprise := env.CreateTestEnterprise("测试企业", &shop.ID)

	enterpriseAccount := env.CreateTestAccount(
		"enterprise_user",
		"password123",
		constants.UserTypeEnterprise,
		nil,
		&enterprise.ID,
	)

	reqBody := dto.CreateAccountRequest{
		Username:     fmt.Sprintf("test_%d", time.Now().UnixNano()),
		Phone:        fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
		Password:     "Password123",
		UserType:     constants.UserTypeEnterprise,
		EnterpriseID: &enterprise.ID,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(enterpriseAccount).Request("POST", "/api/admin/accounts", jsonBody)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusForbidden, resp.StatusCode, "企业账号应被路由层拦截")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.Contains(t, result.Message, "权限", "错误消息应包含权限相关信息")
}

// TestAccountPermission_12_3 代理账号创建自己店铺的账号成功
func TestAccountPermission_12_3(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("代理店铺1", 1, nil)

	agentAccount := env.CreateTestAccount(
		"agent_user",
		"password123",
		constants.UserTypeAgent,
		&shop.ID,
		nil,
	)

	reqBody := dto.CreateAccountRequest{
		Username: fmt.Sprintf("agent_same_%d", time.Now().UnixNano()),
		Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
		Password: "Password123",
		UserType: constants.UserTypeAgent,
		ShopID:   &shop.ID,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(agentAccount).Request("POST", "/api/admin/accounts", jsonBody)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusOK, resp.StatusCode, "代理账号应能创建自己店铺的账号")

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

// TestAccountPermission_12_4 代理账号创建下级店铺的账号成功
func TestAccountPermission_12_4(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	parentShop := env.CreateTestShop("父店铺", 1, nil)
	childShop := env.CreateTestShop("子店铺", 2, &parentShop.ID)

	agentAccount := env.CreateTestAccount(
		"agent_parent",
		"password123",
		constants.UserTypeAgent,
		&parentShop.ID,
		nil,
	)

	reqBody := dto.CreateAccountRequest{
		Username: fmt.Sprintf("agent_child_%d", time.Now().UnixNano()),
		Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
		Password: "Password123",
		UserType: constants.UserTypeAgent,
		ShopID:   &childShop.ID,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(agentAccount).Request("POST", "/api/admin/accounts", jsonBody)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusOK, resp.StatusCode, "代理账号应能创建下级店铺的账号")

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

// TestAccountPermission_12_5 代理账号创建其他店铺的账号失败
func TestAccountPermission_12_5(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop1 := env.CreateTestShop("独立店铺1", 1, nil)
	shop2 := env.CreateTestShop("独立店铺2", 1, nil)

	agentAccount := env.CreateTestAccount(
		"agent_shop1",
		"password123",
		constants.UserTypeAgent,
		&shop1.ID,
		nil,
	)

	reqBody := dto.CreateAccountRequest{
		Username: fmt.Sprintf("agent_other_%d", time.Now().UnixNano()),
		Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
		Password: "Password123",
		UserType: constants.UserTypeAgent,
		ShopID:   &shop2.ID,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(agentAccount).Request("POST", "/api/admin/accounts", jsonBody)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusForbidden, resp.StatusCode, "代理账号不应能创建其他店铺的账号")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.Contains(t, result.Message, "权限", "错误消息应包含权限相关信息")
}

// TestAccountPermission_12_6 代理账号创建平台账号失败
func TestAccountPermission_12_6(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("代理店铺", 1, nil)

	agentAccount := env.CreateTestAccount(
		"agent_try_platform",
		"password123",
		constants.UserTypeAgent,
		&shop.ID,
		nil,
	)

	reqBody := dto.CreateAccountRequest{
		Username: fmt.Sprintf("platform_%d", time.Now().UnixNano()),
		Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
		Password: "Password123",
		UserType: constants.UserTypePlatform,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(agentAccount).Request("POST", "/api/admin/accounts", jsonBody)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusForbidden, resp.StatusCode, "代理账号不应能创建平台账号")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.Contains(t, result.Message, "权限", "错误消息应包含权限相关信息")
}

// TestAccountPermission_12_7 平台账号创建任意类型账号成功
func TestAccountPermission_12_7(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("平台测试店铺", 1, nil)

	platformAccount := env.CreateTestAccount(
		"platform_user",
		"password123",
		constants.UserTypePlatform,
		nil,
		nil,
	)

	t.Run("创建平台账号", func(t *testing.T) {
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("platform_new_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypePlatform,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsUser(platformAccount).Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "平台账号应能创建平台账号")
	})

	t.Run("创建代理账号", func(t *testing.T) {
		time.Sleep(time.Millisecond)
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("agent_new_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypeAgent,
			ShopID:   &shop.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsUser(platformAccount).Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "平台账号应能创建代理账号")
	})
}

// TestAccountPermission_12_8 超级管理员创建任意类型账号成功
func TestAccountPermission_12_8(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("超管测试店铺", 1, nil)
	enterprise := env.CreateTestEnterprise("超管测试企业", &shop.ID)

	t.Run("创建平台账号", func(t *testing.T) {
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("superadmin_platform_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypePlatform,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "超级管理员应能创建平台账号")
	})

	t.Run("创建代理账号", func(t *testing.T) {
		time.Sleep(time.Millisecond)
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("superadmin_agent_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypeAgent,
			ShopID:   &shop.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "超级管理员应能创建代理账号")
	})

	t.Run("创建企业账号", func(t *testing.T) {
		time.Sleep(time.Millisecond)
		reqBody := dto.CreateAccountRequest{
			Username:     fmt.Sprintf("superadmin_ent_%d", time.Now().UnixNano()),
			Phone:        fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password:     "Password123",
			UserType:     constants.UserTypeEnterprise,
			EnterpriseID: &enterprise.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "超级管理员应能创建企业账号")
	})
}

// TestAccountPermission_12_9 查询不存在的账号返回统一错误
func TestAccountPermission_12_9(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("查询测试店铺", 1, nil)
	agentAccount := env.CreateTestAccount(
		"agent_query",
		"password123",
		constants.UserTypeAgent,
		&shop.ID,
		nil,
	)

	resp, err := env.AsUser(agentAccount).Request("GET", "/api/admin/accounts/99999", nil)
	require.NoError(t, err)

	// GORM 自动过滤后，查询不存在的账号返回 "账号不存在" (400)
	// 或 "无权限操作该资源或资源不存在" (403)
	assert.True(t,
		resp.StatusCode == fiber.StatusBadRequest ||
			resp.StatusCode == fiber.StatusForbidden ||
			resp.StatusCode == fiber.StatusNotFound,
		"查询不存在的账号应返回错误状态码")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.NotEqual(t, 0, result.Code, "业务码应不为0")
}

// TestAccountPermission_12_10 查询越权的账号返回相同错误消息
func TestAccountPermission_12_10(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop1 := env.CreateTestShop("越权测试店铺1", 1, nil)
	shop2 := env.CreateTestShop("越权测试店铺2", 1, nil)

	agentAccount1 := env.CreateTestAccount(
		"agent_auth1",
		"password123",
		constants.UserTypeAgent,
		&shop1.ID,
		nil,
	)

	agentAccount2 := env.CreateTestAccount(
		"agent_auth2",
		"password123",
		constants.UserTypeAgent,
		&shop2.ID,
		nil,
	)

	resp, err := env.AsUser(agentAccount1).Request(
		"GET",
		fmt.Sprintf("/api/admin/accounts/%d", agentAccount2.ID),
		nil,
	)
	require.NoError(t, err)

	// GORM 自动过滤使越权查询返回与不存在相同的错误，防止信息泄露
	assert.True(t,
		resp.StatusCode == fiber.StatusBadRequest ||
			resp.StatusCode == fiber.StatusForbidden ||
			resp.StatusCode == fiber.StatusNotFound,
		"查询越权账号应返回错误状态码")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.NotEqual(t, 0, result.Code, "业务码应不为0")
}

// TestAccountPermission_12_11 代理账号更新其他店铺的账号失败
func TestAccountPermission_12_11(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop1 := env.CreateTestShop("更新测试店铺1", 1, nil)
	shop2 := env.CreateTestShop("更新测试店铺2", 1, nil)

	agentAccount1 := env.CreateTestAccount(
		"agent_update1",
		"password123",
		constants.UserTypeAgent,
		&shop1.ID,
		nil,
	)

	agentAccount2 := env.CreateTestAccount(
		"agent_update2",
		"password123",
		constants.UserTypeAgent,
		&shop2.ID,
		nil,
	)

	newUsername := "updated_username"
	reqBody := dto.UpdateAccountRequest{
		Username: &newUsername,
	}
	jsonBody, _ := json.Marshal(reqBody)

	resp, err := env.AsUser(agentAccount1).Request(
		"PUT",
		fmt.Sprintf("/api/admin/accounts/%d", agentAccount2.ID),
		jsonBody,
	)
	require.NoError(t, err)

	assert.Equal(t, fiber.StatusForbidden, resp.StatusCode, "代理账号不应能更新其他店铺的账号")

	var result response.Response
	err = json.NewDecoder(resp.Body).Decode(&result)
	require.NoError(t, err)
	assert.Contains(t, result.Message, "权限", "错误消息应包含权限相关信息")
}

// TestEnterpriseAccountRouteBlocking 测试企业账号访问各类型账号管理接口的路由层拦截
func TestEnterpriseAccountRouteBlocking(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("路由拦截测试店铺", 1, nil)
	enterprise := env.CreateTestEnterprise("路由拦截测试企业", &shop.ID)

	enterpriseAccount := env.CreateTestAccount(
		"enterprise_route_test",
		"password123",
		constants.UserTypeEnterprise,
		nil,
		&enterprise.ID,
	)

	t.Run("企业账号访问企业账号列表接口被拦截", func(t *testing.T) {
		resp, err := env.AsUser(enterpriseAccount).Request("GET", "/api/admin/accounts", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusForbidden, resp.StatusCode)
	})

	t.Run("企业账号访问企业账号详情接口被拦截", func(t *testing.T) {
		resp, err := env.AsUser(enterpriseAccount).Request("GET", "/api/admin/accounts/1", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusForbidden, resp.StatusCode)
	})

	t.Run("企业账号访问创建企业账号接口被拦截", func(t *testing.T) {
		reqBody := dto.CreateAccountRequest{
			Username:     fmt.Sprintf("test_%d", time.Now().UnixNano()),
			Phone:        fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password:     "Password123",
			UserType:     constants.UserTypeEnterprise,
			EnterpriseID: &enterprise.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsUser(enterpriseAccount).Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusForbidden, resp.StatusCode)
	})
}

// TestAgentAccountHierarchyPermission 测试代理账号的层级权限
func TestAgentAccountHierarchyPermission(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	level1Shop := env.CreateTestShop("一级店铺", 1, nil)
	level2Shop := env.CreateTestShop("二级店铺", 2, &level1Shop.ID)
	level3Shop := env.CreateTestShop("三级店铺", 3, &level2Shop.ID)

	level2Agent := env.CreateTestAccount(
		"level2_agent",
		"password123",
		constants.UserTypeAgent,
		&level2Shop.ID,
		nil,
	)

	t.Run("二级代理可以管理三级店铺账号", func(t *testing.T) {
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("level3_new_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypeAgent,
			ShopID:   &level3Shop.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsUser(level2Agent).Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode, "二级代理应能管理三级店铺账号")
	})

	t.Run("二级代理不能管理一级店铺账号", func(t *testing.T) {
		reqBody := dto.CreateAccountRequest{
			Username: fmt.Sprintf("level1_new_%d", time.Now().UnixNano()),
			Phone:    fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000),
			Password: "Password123",
			UserType: constants.UserTypeAgent,
			ShopID:   &level1Shop.ID,
		}
		jsonBody, _ := json.Marshal(reqBody)

		resp, err := env.AsUser(level2Agent).Request("POST", "/api/admin/accounts", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusForbidden, resp.StatusCode, "二级代理不应能管理一级店铺账号")
	})
}
