// Package account 提供账号管理的业务逻辑服务
// 包含账号创建、查询、更新、删除、密码管理等功能
package account

import (
	"context"
	stdErrors "errors"
	"fmt"
	"strings"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store"
	"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/jackc/pgx/v5/pgconn"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// ShopStoreInterface 店铺存储接口（仅用于获取店铺信息）
type ShopStoreInterface interface {
	GetByIDs(ctx context.Context, ids []uint) ([]*model.Shop, error)
}

// Service 账号业务服务
type Service struct {
	accountStore     *postgres.AccountStore
	roleStore        *postgres.RoleStore
	accountRoleStore *postgres.AccountRoleStore
	shopRoleStore    *postgres.ShopRoleStore
	shopStore        ShopStoreInterface
	enterpriseStore  middleware.EnterpriseStoreInterface
	auditService     AuditServiceInterface
	wecomMembers     WeComMemberFinder
}

type AuditServiceInterface interface {
	LogOperation(ctx context.Context, log *model.AccountOperationLog)
}

// WeComMemberFinder 定义账号绑定时校验应用可见成员的边界。
type WeComMemberFinder interface {
	GetVisible(ctx context.Context, applicationID uint, userID string) (*model.WeComMember, error)
}

// New 创建账号服务
func New(
	accountStore *postgres.AccountStore,
	roleStore *postgres.RoleStore,
	accountRoleStore *postgres.AccountRoleStore,
	shopRoleStore *postgres.ShopRoleStore,
	shopStore ShopStoreInterface,
	enterpriseStore middleware.EnterpriseStoreInterface,
	auditService AuditServiceInterface,
) *Service {
	return &Service{
		accountStore:     accountStore,
		roleStore:        roleStore,
		accountRoleStore: accountRoleStore,
		shopRoleStore:    shopRoleStore,
		shopStore:        shopStore,
		enterpriseStore:  enterpriseStore,
		auditService:     auditService,
	}
}

// SetWeComMemberFinder 注入企业微信应用可见成员查询边界。
func (s *Service) SetWeComMemberFinder(finder WeComMemberFinder) {
	s.wecomMembers = finder
}

// Create 创建账号
func (s *Service) Create(ctx context.Context, req *dto.CreateAccountRequest) (*model.Account, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	userType := middleware.GetUserTypeFromContext(ctx)

	if userType == constants.UserTypeEnterprise {
		return nil, errors.New(errors.CodeForbidden, "企业账号不允许创建账号")
	}

	if userType == constants.UserTypeAgent && req.UserType == constants.UserTypePlatform {
		return nil, errors.New(errors.CodeForbidden, "无权限创建平台账号")
	}

	if req.UserType == constants.UserTypeAgent && req.ShopID == nil {
		return nil, errors.New(errors.CodeInvalidParam, "代理账号必须提供店铺ID")
	}

	if req.UserType == constants.UserTypeEnterprise && req.EnterpriseID == nil {
		return nil, errors.New(errors.CodeInvalidParam, "企业账号必须提供企业ID")
	}

	if req.UserType == constants.UserTypeAgent && req.ShopID != nil {
		if err := middleware.CanManageShop(ctx, *req.ShopID); err != nil {
			return nil, err
		}
	}

	if req.UserType == constants.UserTypeEnterprise && req.EnterpriseID != nil {
		if err := middleware.CanManageEnterprise(ctx, *req.EnterpriseID, s.enterpriseStore); err != nil {
			return nil, err
		}
	}

	existing, err := s.accountStore.GetByUsername(ctx, req.Username)
	if err == nil && existing != nil {
		return nil, errors.New(errors.CodeUsernameExists, "用户名已存在")
	}

	existing, err = s.accountStore.GetByPhone(ctx, req.Phone)
	if err == nil && existing != nil {
		return nil, errors.New(errors.CodePhoneExists, "手机号已存在")
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "密码哈希失败")
	}

	account := &model.Account{
		Username:     req.Username,
		Phone:        req.Phone,
		Password:     string(hashedPassword),
		UserType:     req.UserType,
		ShopID:       req.ShopID,
		EnterpriseID: req.EnterpriseID,
		Status:       constants.StatusEnabled,
	}

	if err := s.accountStore.Create(ctx, account); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建账号失败")
	}

	// 代理账号自动分配该店铺的默认角色
	if req.UserType == constants.UserTypeAgent && req.ShopID != nil {
		roleIDs, err := s.shopRoleStore.GetRoleIDsByShopID(ctx, *req.ShopID)
		if err == nil {
			for _, roleID := range roleIDs {
				ar := &model.AccountRole{
					AccountID: account.ID,
					RoleID:    roleID,
					Status:    constants.StatusEnabled,
					Creator:   currentUserID,
					Updater:   currentUserID,
				}
				_ = s.accountRoleStore.Create(ctx, ar)
			}
		}
	}

	currentAccount, _ := s.accountStore.GetByID(ctx, currentUserID)
	operatorName := ""
	if currentAccount != nil {
		operatorName = currentAccount.Username
	}

	afterData := model.JSONB{
		"id":            account.ID,
		"username":      account.Username,
		"phone":         account.Phone,
		"user_type":     account.UserType,
		"shop_id":       account.ShopID,
		"enterprise_id": account.EnterpriseID,
		"status":        account.Status,
	}

	requestID := middleware.GetRequestIDFromContext(ctx)
	ipAddress := middleware.GetIPFromContext(ctx)
	userAgent := middleware.GetUserAgentFromContext(ctx)

	s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:      currentUserID,
		OperatorType:    userType,
		OperatorName:    operatorName,
		TargetAccountID: &account.ID,
		TargetUsername:  &account.Username,
		TargetUserType:  &account.UserType,
		OperationType:   "create",
		OperationDesc:   fmt.Sprintf("创建账号: %s", account.Username),
		AfterData:       afterData,
		RequestID:       requestID,
		IPAddress:       ipAddress,
		UserAgent:       userAgent,
	})

	return account, nil
}

// Get 获取账号
func (s *Service) Get(ctx context.Context, id uint) (*dto.AccountResponse, error) {
	account, err := s.accountStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeAccountNotFound, "账号不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}
	accounts := []*model.Account{account}
	return s.toAccountResponse(account, s.loadShopNames(ctx, accounts), s.loadEnterpriseNames(ctx, accounts)), nil
}

// BindWeCom 将系统账号绑定到管理员明确选择的企微应用可见成员。
func (s *Service) BindWeCom(ctx context.Context, accountID uint, request dto.BindAccountWeComRequest) (*dto.AccountResponse, error) {
	operatorID := middleware.GetUserIDFromContext(ctx)
	operatorType := middleware.GetUserTypeFromContext(ctx)
	if operatorID == 0 {
		return nil, errors.New(errors.CodeUnauthorized)
	}
	if operatorType != constants.UserTypeSuperAdmin && operatorType != constants.UserTypePlatform {
		return nil, errors.New(errors.CodeForbidden)
	}
	if s.wecomMembers == nil || request.ApplicationID == 0 || strings.TrimSpace(request.UserID) == "" {
		return nil, errors.New(errors.CodeInvalidParam)
	}
	account, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询待绑定账号失败")
	}
	member, err := s.wecomMembers.GetVisible(ctx, request.ApplicationID, request.UserID)
	if err != nil {
		return nil, err
	}
	beforeData := model.JSONB{
		"wecom_corp_id": account.WeComCorpID, "wecom_userid": account.WeComUserID,
		"wecom_name": account.WeComName,
	}
	if err := s.accountStore.BindWeCom(ctx, accountID, member.CorpID, member.UserID, member.Name, operatorID); err != nil {
		var pgErr *pgconn.PgError
		if stdErrors.As(err, &pgErr) && pgErr.Code == "23505" {
			return nil, errors.New(errors.CodeConflict, "该企业微信成员已绑定其他系统账号")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "绑定企业微信成员失败")
	}
	account.WeComCorpID = member.CorpID
	account.WeComUserID = member.UserID
	account.WeComName = member.Name
	account.Updater = operatorID
	if s.auditService != nil {
		operatorName := ""
		if operator, getErr := s.accountStore.GetByID(ctx, operatorID); getErr == nil {
			operatorName = operator.Username
		}
		s.auditService.LogOperation(ctx, &model.AccountOperationLog{
			OperatorID: operatorID, OperatorType: operatorType, OperatorName: operatorName,
			TargetAccountID: &account.ID, TargetUsername: &account.Username, TargetUserType: &account.UserType,
			OperationType: "bind_wecom", OperationDesc: fmt.Sprintf("绑定账号企业微信成员: %s", account.Username),
			BeforeData: beforeData, AfterData: model.JSONB{
				"wecom_corp_id": member.CorpID, "wecom_userid": member.UserID, "wecom_name": member.Name,
			}, RequestID: middleware.GetRequestIDFromContext(ctx), IPAddress: middleware.GetIPFromContext(ctx),
			UserAgent: middleware.GetUserAgentFromContext(ctx),
		})
	}
	accounts := []*model.Account{account}
	return s.toAccountResponse(account, s.loadShopNames(ctx, accounts), s.loadEnterpriseNames(ctx, accounts)), nil
}

// Update 更新账号
func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateAccountRequest) (*model.Account, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	account, err := s.accountStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	userType := middleware.GetUserTypeFromContext(ctx)

	if userType == constants.UserTypeAgent {
		if account.ShopID == nil {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该账号")
		}
		if err := middleware.CanManageShop(ctx, *account.ShopID); err != nil {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
	}

	beforeData := model.JSONB{
		"username": account.Username,
		"phone":    account.Phone,
		"status":   account.Status,
	}

	if req.Username != nil {
		existing, err := s.accountStore.GetByUsername(ctx, *req.Username)
		if err == nil && existing != nil && existing.ID != id {
			return nil, errors.New(errors.CodeUsernameExists, "用户名已存在")
		}
		account.Username = *req.Username
	}

	if req.Phone != nil {
		existing, err := s.accountStore.GetByPhone(ctx, *req.Phone)
		if err == nil && existing != nil && existing.ID != id {
			return nil, errors.New(errors.CodePhoneExists, "手机号已存在")
		}
		account.Phone = *req.Phone
	}

	if req.Password != nil {
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
		if err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "密码哈希失败")
		}
		account.Password = string(hashedPassword)
	}

	if req.Status != nil {
		account.Status = *req.Status
	}

	account.Updater = currentUserID

	if err := s.accountStore.Update(ctx, account); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "更新账号失败")
	}

	currentAccount, _ := s.accountStore.GetByID(ctx, currentUserID)
	operatorName := ""
	if currentAccount != nil {
		operatorName = currentAccount.Username
	}

	afterData := model.JSONB{
		"username": account.Username,
		"phone":    account.Phone,
		"status":   account.Status,
	}

	requestID := middleware.GetRequestIDFromContext(ctx)
	ipAddress := middleware.GetIPFromContext(ctx)
	userAgent := middleware.GetUserAgentFromContext(ctx)

	s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:      currentUserID,
		OperatorType:    userType,
		OperatorName:    operatorName,
		TargetAccountID: &account.ID,
		TargetUsername:  &account.Username,
		TargetUserType:  &account.UserType,
		OperationType:   "update",
		OperationDesc:   fmt.Sprintf("更新账号: %s", account.Username),
		BeforeData:      beforeData,
		AfterData:       afterData,
		RequestID:       requestID,
		IPAddress:       ipAddress,
		UserAgent:       userAgent,
	})

	return account, nil
}

// Delete 软删除账号
func (s *Service) Delete(ctx context.Context, id uint) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	account, err := s.accountStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	userType := middleware.GetUserTypeFromContext(ctx)

	if userType == constants.UserTypeAgent {
		if account.ShopID == nil {
			return errors.New(errors.CodeForbidden, "无权限操作该账号")
		}
		if err := middleware.CanManageShop(ctx, *account.ShopID); err != nil {
			return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
	}

	beforeData := model.JSONB{
		"id":       account.ID,
		"username": account.Username,
		"phone":    account.Phone,
		"status":   account.Status,
	}

	if err := s.accountStore.Delete(ctx, id); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "删除账号失败")
	}

	currentAccount, _ := s.accountStore.GetByID(ctx, currentUserID)
	operatorName := ""
	if currentAccount != nil {
		operatorName = currentAccount.Username
	}

	requestID := middleware.GetRequestIDFromContext(ctx)
	ipAddress := middleware.GetIPFromContext(ctx)
	userAgent := middleware.GetUserAgentFromContext(ctx)

	s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:      currentUserID,
		OperatorType:    userType,
		OperatorName:    operatorName,
		TargetAccountID: &account.ID,
		TargetUsername:  &account.Username,
		TargetUserType:  &account.UserType,
		OperationType:   "delete",
		OperationDesc:   fmt.Sprintf("删除账号: %s", account.Username),
		BeforeData:      beforeData,
		RequestID:       requestID,
		IPAddress:       ipAddress,
		UserAgent:       userAgent,
	})

	return nil
}

// List 查询账号列表
func (s *Service) List(ctx context.Context, req *dto.AccountListRequest) ([]*dto.AccountResponse, int64, error) {
	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "id DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.Username != "" {
		filters["username"] = req.Username
	}
	if req.Phone != "" {
		filters["phone"] = req.Phone
	}
	if req.UserType != nil {
		filters["user_type"] = *req.UserType
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}
	if req.ShopID != nil {
		filters["shop_id"] = *req.ShopID
	}
	if req.EnterpriseID != nil {
		filters["enterprise_id"] = *req.EnterpriseID
	}

	accounts, total, err := s.accountStore.List(ctx, opts, filters)
	if err != nil {
		return nil, 0, err
	}

	shopMap := s.loadShopNames(ctx, accounts)
	enterpriseMap := s.loadEnterpriseNames(ctx, accounts)

	responses := make([]*dto.AccountResponse, 0, len(accounts))
	for _, acc := range accounts {
		resp := s.toAccountResponse(acc, shopMap, enterpriseMap)
		responses = append(responses, resp)
	}

	return responses, total, nil
}

// AssignRoles 为账号分配角色（支持空数组清空所有角色，超级管理员禁止分配）
func (s *Service) AssignRoles(ctx context.Context, accountID uint, roleIDs []uint) ([]*model.AccountRole, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	account, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	userType := middleware.GetUserTypeFromContext(ctx)

	if userType == constants.UserTypeAgent {
		if account.ShopID == nil {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该账号")
		}
		if err := middleware.CanManageShop(ctx, *account.ShopID); err != nil {
			return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
	}

	if account.UserType == constants.UserTypeSuperAdmin {
		return nil, errors.New(errors.CodeInvalidParam, "超级管理员不允许分配角色")
	}

	// 空数组：清空所有角色
	if len(roleIDs) == 0 {
		if err := s.accountRoleStore.DeleteByAccountID(ctx, accountID); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "清空账号角色失败")
		}
		return []*model.AccountRole{}, nil
	}

	maxRoles := constants.GetMaxRolesForUserType(account.UserType)
	if maxRoles == 0 {
		return nil, errors.New(errors.CodeInvalidParam, "该用户类型不需要分配角色")
	}

	existingCount, err := s.accountRoleStore.CountByAccountID(ctx, accountID)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "统计现有角色数量失败")
	}

	newRoleCount := 0
	for _, roleID := range roleIDs {
		exists, _ := s.accountRoleStore.Exists(ctx, accountID, roleID)
		if !exists {
			newRoleCount++
		}
	}

	if maxRoles != -1 && int(existingCount)+newRoleCount > maxRoles {
		return nil, errors.New(errors.CodeInvalidParam, fmt.Sprintf("该用户类型最多只能分配 %d 个角色", maxRoles))
	}

	for _, roleID := range roleIDs {
		role, err := s.roleStore.GetByID(ctx, roleID)
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				return nil, errors.New(errors.CodeRoleNotFound, fmt.Sprintf("角色 %d 不存在", roleID))
			}
			return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色失败")
		}

		if !constants.IsRoleTypeMatchUserType(role.RoleType, account.UserType) {
			return nil, errors.New(errors.CodeInvalidParam, "角色类型与账号类型不匹配")
		}
	}

	var ars []*model.AccountRole
	for _, roleID := range roleIDs {
		exists, _ := s.accountRoleStore.Exists(ctx, accountID, roleID)
		if exists {
			continue
		}

		ar := &model.AccountRole{
			AccountID: accountID,
			RoleID:    roleID,
			Status:    constants.StatusEnabled,
			Creator:   currentUserID,
			Updater:   currentUserID,
		}
		if err := s.accountRoleStore.Create(ctx, ar); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "创建账号-角色关联失败")
		}
		ars = append(ars, ar)
	}

	currentAccount, _ := s.accountStore.GetByID(ctx, currentUserID)
	operatorName := ""
	if currentAccount != nil {
		operatorName = currentAccount.Username
	}

	afterData := model.JSONB{
		"role_ids": roleIDs,
	}

	requestID := middleware.GetRequestIDFromContext(ctx)
	ipAddress := middleware.GetIPFromContext(ctx)
	userAgent := middleware.GetUserAgentFromContext(ctx)

	s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:      currentUserID,
		OperatorType:    userType,
		OperatorName:    operatorName,
		TargetAccountID: &account.ID,
		TargetUsername:  &account.Username,
		TargetUserType:  &account.UserType,
		OperationType:   "assign_roles",
		OperationDesc:   fmt.Sprintf("为账号 %s 分配角色", account.Username),
		AfterData:       afterData,
		RequestID:       requestID,
		IPAddress:       ipAddress,
		UserAgent:       userAgent,
	})

	return ars, nil
}

// GetRoles 获取账号的所有角色
func (s *Service) GetRoles(ctx context.Context, accountID uint) ([]*model.Role, error) {
	// 检查账号存在
	_, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeAccountNotFound, "账号不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	// 获取角色 ID 列表
	roleIDs, err := s.accountRoleStore.GetRoleIDsByAccountID(ctx, accountID)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取账号角色 ID 失败")
	}

	if len(roleIDs) == 0 {
		return []*model.Role{}, nil
	}

	// 获取角色详情
	return s.roleStore.GetByIDs(ctx, roleIDs)
}

// RemoveRole 移除账号的角色
func (s *Service) RemoveRole(ctx context.Context, accountID, roleID uint) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	account, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	userType := middleware.GetUserTypeFromContext(ctx)

	if userType == constants.UserTypeAgent {
		if account.ShopID == nil {
			return errors.New(errors.CodeForbidden, "无权限操作该账号")
		}
		if err := middleware.CanManageShop(ctx, *account.ShopID); err != nil {
			return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
		}
	}

	if err := s.accountRoleStore.Delete(ctx, accountID, roleID); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "删除账号-角色关联失败")
	}

	currentAccount, _ := s.accountStore.GetByID(ctx, currentUserID)
	operatorName := ""
	if currentAccount != nil {
		operatorName = currentAccount.Username
	}

	afterData := model.JSONB{
		"removed_role_id": roleID,
	}

	requestID := middleware.GetRequestIDFromContext(ctx)
	ipAddress := middleware.GetIPFromContext(ctx)
	userAgent := middleware.GetUserAgentFromContext(ctx)

	s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:      currentUserID,
		OperatorType:    userType,
		OperatorName:    operatorName,
		TargetAccountID: &account.ID,
		TargetUsername:  &account.Username,
		TargetUserType:  &account.UserType,
		OperationType:   "remove_role",
		OperationDesc:   fmt.Sprintf("移除账号 %s 的角色", account.Username),
		AfterData:       afterData,
		RequestID:       requestID,
		IPAddress:       ipAddress,
		UserAgent:       userAgent,
	})

	return nil
}

// ValidatePassword 验证密码
func (s *Service) ValidatePassword(plainPassword, hashedPassword string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(plainPassword))
	return err == nil
}

// UpdatePassword 修改账号密码（管理员重置场景，无需旧密码）
func (s *Service) UpdatePassword(ctx context.Context, accountID uint, newPassword string) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	_, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeAccountNotFound, "账号不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "密码哈希失败")
	}

	if err := s.accountStore.UpdatePassword(ctx, accountID, string(hashedPassword), currentUserID); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "更新密码失败")
	}

	return nil
}

// UpdateStatus 修改账号状态（启用/禁用）
func (s *Service) UpdateStatus(ctx context.Context, accountID uint, status int) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	_, err := s.accountStore.GetByID(ctx, accountID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeAccountNotFound, "账号不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取账号失败")
	}

	if err := s.accountStore.UpdateStatus(ctx, accountID, status, currentUserID); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "更新状态失败")
	}

	return nil
}

// ListPlatformAccounts 查询平台账号列表（自动筛选 user_type IN (1, 2)）
func (s *Service) ListPlatformAccounts(ctx context.Context, req *dto.PlatformAccountListRequest) ([]*model.Account, int64, error) {
	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "id DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.Username != "" {
		filters["username"] = req.Username
	}
	if req.Phone != "" {
		filters["phone"] = req.Phone
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}

	return s.accountStore.ListPlatformAccounts(ctx, opts, filters)
}

// CreateSystemAccount 系统内部创建账号方法，用于系统初始化场景（绕过当前用户检查）
func (s *Service) CreateSystemAccount(ctx context.Context, account *model.Account) error {
	if account.Username == "" {
		return errors.New(errors.CodeInvalidParam, "用户名不能为空")
	}
	if account.Phone == "" {
		return errors.New(errors.CodeInvalidParam, "手机号不能为空")
	}
	if account.Password == "" {
		return errors.New(errors.CodeInvalidParam, "密码不能为空")
	}

	existing, err := s.accountStore.GetByUsername(ctx, account.Username)
	if err == nil && existing != nil {
		return errors.New(errors.CodeUsernameExists, "用户名已存在")
	}

	existing, err = s.accountStore.GetByPhone(ctx, account.Phone)
	if err == nil && existing != nil {
		return errors.New(errors.CodePhoneExists, "手机号已存在")
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(account.Password), bcrypt.DefaultCost)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "密码哈希失败")
	}
	account.Password = string(hashedPassword)

	if err := s.accountStore.Create(ctx, account); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "创建账号失败")
	}

	return nil
}

// loadShopNames 批量加载店铺名称
func (s *Service) loadShopNames(ctx context.Context, accounts []*model.Account) map[uint]string {
	shopIDs := make([]uint, 0)
	shopIDSet := make(map[uint]bool)

	for _, acc := range accounts {
		if acc.ShopID != nil && *acc.ShopID > 0 && !shopIDSet[*acc.ShopID] {
			shopIDs = append(shopIDs, *acc.ShopID)
			shopIDSet[*acc.ShopID] = true
		}
	}

	shopMap := make(map[uint]string)
	if len(shopIDs) > 0 {
		shops, err := s.shopStore.GetByIDs(ctx, shopIDs)
		if err == nil {
			for _, shop := range shops {
				shopMap[shop.ID] = shop.ShopName
			}
		}
	}
	return shopMap
}

// loadEnterpriseNames 批量加载企业名称
func (s *Service) loadEnterpriseNames(ctx context.Context, accounts []*model.Account) map[uint]string {
	enterpriseIDs := make([]uint, 0)
	enterpriseIDSet := make(map[uint]bool)

	for _, acc := range accounts {
		if acc.EnterpriseID != nil && *acc.EnterpriseID > 0 && !enterpriseIDSet[*acc.EnterpriseID] {
			enterpriseIDs = append(enterpriseIDs, *acc.EnterpriseID)
			enterpriseIDSet[*acc.EnterpriseID] = true
		}
	}

	enterpriseMap := make(map[uint]string)
	if len(enterpriseIDs) > 0 {
		enterprises, err := s.enterpriseStore.GetByIDs(ctx, enterpriseIDs)
		if err == nil {
			for _, ent := range enterprises {
				enterpriseMap[ent.ID] = ent.EnterpriseName
			}
		}
	}
	return enterpriseMap
}

// toAccountResponse 组装账号响应，填充关联名称
func (s *Service) toAccountResponse(acc *model.Account, shopMap map[uint]string, enterpriseMap map[uint]string) *dto.AccountResponse {
	resp := &dto.AccountResponse{
		ID:           acc.ID,
		Username:     acc.Username,
		Phone:        acc.Phone,
		UserType:     acc.UserType,
		ShopID:       acc.ShopID,
		EnterpriseID: acc.EnterpriseID,
		WeComCorpID:  acc.WeComCorpID,
		WeComUserID:  acc.WeComUserID,
		WeComName:    acc.WeComName,
		WeComBound:   acc.WeComCorpID != "" && acc.WeComUserID != "",
		Status:       acc.Status,
		StatusName:   constants.GetStatusName(acc.Status),
		Creator:      acc.Creator,
		Updater:      acc.Updater,
		CreatedAt:    acc.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:    acc.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	if acc.ShopID != nil && *acc.ShopID > 0 {
		resp.ShopName = shopMap[*acc.ShopID]
	}

	if acc.EnterpriseID != nil && *acc.EnterpriseID > 0 {
		resp.EnterpriseName = enterpriseMap[*acc.EnterpriseID]
	}

	return resp
}
