package shop

import (
	"context"

	"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"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type Service struct {
	shopStore        *postgres.ShopStore
	accountStore     *postgres.AccountStore
	shopRoleStore    *postgres.ShopRoleStore
	roleStore        *postgres.RoleStore
	accountRoleStore *postgres.AccountRoleStore
	agentWalletStore *postgres.AgentWalletStore
}

func New(
	shopStore *postgres.ShopStore,
	accountStore *postgres.AccountStore,
	shopRoleStore *postgres.ShopRoleStore,
	roleStore *postgres.RoleStore,
	accountRoleStore *postgres.AccountRoleStore,
	agentWalletStore *postgres.AgentWalletStore,
) *Service {
	return &Service{
		shopStore:        shopStore,
		accountStore:     accountStore,
		shopRoleStore:    shopRoleStore,
		roleStore:        roleStore,
		accountRoleStore: accountRoleStore,
		agentWalletStore: agentWalletStore,
	}
}

func (s *Service) Create(ctx context.Context, req *dto.CreateShopRequest) (*dto.ShopResponse, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	existing, err := s.shopStore.GetByCode(ctx, req.ShopCode)
	if err == nil && existing != nil {
		return nil, errors.New(errors.CodeShopCodeExists, "店铺编号已存在")
	}

	level := 1
	if req.ParentID != nil {
		parent, err := s.shopStore.GetByID(ctx, *req.ParentID)
		if err != nil {
			return nil, errors.New(errors.CodeInvalidParentID, "上级店铺不存在或无效")
		}
		level = parent.Level + 1
		if level > constants.ShopMaxLevel {
			return nil, errors.New(errors.CodeShopLevelExceeded, "店铺层级不能超过 7 级")
		}
	}

	existingAccount, err := s.accountStore.GetByUsername(ctx, req.InitUsername)
	if err == nil && existingAccount != nil {
		return nil, errors.New(errors.CodeUsernameExists, "初始账号用户名已存在")
	}

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

	// 验证默认角色：必须存在、是客户角色且已启用
	defaultRole, err := s.roleStore.GetByID(ctx, req.DefaultRoleID)
	if err != nil {
		return nil, errors.New(errors.CodeNotFound, "请选择默认角色")
	}
	if defaultRole.RoleType != constants.RoleTypeCustomer {
		return nil, errors.New(errors.CodeInvalidParam, "店铺默认角色必须是客户角色")
	}
	if defaultRole.Status != constants.StatusEnabled {
		return nil, errors.New(errors.CodeInvalidParam, "默认角色已禁用")
	}

	shop := &model.Shop{
		ShopName:     req.ShopName,
		ShopCode:     req.ShopCode,
		ParentID:     req.ParentID,
		Level:        level,
		ContactName:  req.ContactName,
		ContactPhone: req.ContactPhone,
		Province:     req.Province,
		City:         req.City,
		District:     req.District,
		Address:      req.Address,
		Status:       constants.ShopStatusEnabled,
	}
	shop.Creator = currentUserID
	shop.Updater = currentUserID

	if err := s.shopStore.Create(ctx, shop); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建店铺失败")
	}

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

	account := &model.Account{
		Username: req.InitUsername,
		Phone:    req.InitPhone,
		Password: string(hashedPassword),
		UserType: constants.UserTypeAgent,
		ShopID:   &shop.ID,
		Status:   constants.StatusEnabled,
	}
	account.Creator = currentUserID
	account.Updater = currentUserID

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

	// 为初始账号分配默认角色
	accountRole := &model.AccountRole{
		AccountID: account.ID,
		RoleID:    req.DefaultRoleID,
		Status:    constants.StatusEnabled,
		Creator:   currentUserID,
		Updater:   currentUserID,
	}
	if err := s.accountRoleStore.Create(ctx, accountRole); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "为初始账号分配角色失败")
	}

	// 设置店铺默认角色
	shopRole := &model.ShopRole{
		ShopID:  shop.ID,
		RoleID:  req.DefaultRoleID,
		Status:  constants.StatusEnabled,
		Creator: currentUserID,
		Updater: currentUserID,
	}
	if err := s.shopRoleStore.BatchCreate(ctx, []*model.ShopRole{shopRole}); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "设置店铺默认角色失败")
	}

	// 初始化店铺代理钱包：主钱包 + 分佣钱包
	// 新店铺必须有两个钱包才能参与充值和分佣体系
	wallets := []*model.AgentWallet{
		{
			ShopID:     shop.ID,
			WalletType: constants.AgentWalletTypeMain,
			Balance:    0,
			Currency:   "CNY",
			Status:     constants.AgentWalletStatusNormal,
			ShopIDTag:  shop.ID,
		},
		{
			ShopID:     shop.ID,
			WalletType: constants.AgentWalletTypeCommission,
			Balance:    0,
			Currency:   "CNY",
			Status:     constants.AgentWalletStatusNormal,
			ShopIDTag:  shop.ID,
		},
	}
	for _, wallet := range wallets {
		if err := s.agentWalletStore.Create(ctx, wallet); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "初始化店铺钱包失败")
		}
	}

	return &dto.ShopResponse{
		ID:           shop.ID,
		ShopName:     shop.ShopName,
		ShopCode:     shop.ShopCode,
		ParentID:     shop.ParentID,
		Level:        shop.Level,
		ContactName:  shop.ContactName,
		ContactPhone: shop.ContactPhone,
		Province:     shop.Province,
		City:         shop.City,
		District:     shop.District,
		Address:      shop.Address,
		Status:       shop.Status,
		StatusName:   constants.GetStatusName(shop.Status),
		CreatedAt:    shop.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:    shop.UpdatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateShopRequest) (*dto.ShopResponse, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	shop, err := s.shopStore.GetByID(ctx, id)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	shop.ShopName = req.ShopName
	shop.ContactName = req.ContactName
	shop.ContactPhone = req.ContactPhone
	shop.Province = req.Province
	shop.City = req.City
	shop.District = req.District
	shop.Address = req.Address
	shop.Status = req.Status
	shop.Updater = currentUserID

	if err := s.shopStore.Update(ctx, shop); err != nil {
		return nil, err
	}

	return &dto.ShopResponse{
		ID:           shop.ID,
		ShopName:     shop.ShopName,
		ShopCode:     shop.ShopCode,
		ParentID:     shop.ParentID,
		Level:        shop.Level,
		ContactName:  shop.ContactName,
		ContactPhone: shop.ContactPhone,
		Province:     shop.Province,
		City:         shop.City,
		District:     shop.District,
		Address:      shop.Address,
		Status:       shop.Status,
		StatusName:   constants.GetStatusName(shop.Status),
		CreatedAt:    shop.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:    shop.UpdatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

// Disable 禁用店铺
func (s *Service) Disable(ctx context.Context, id uint) error {
	// 获取当前用户 ID
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 查询店铺
	shop, err := s.shopStore.GetByID(ctx, id)
	if err != nil {
		return errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	// 更新状态
	shop.Status = constants.StatusDisabled
	shop.Updater = currentUserID

	return s.shopStore.Update(ctx, shop)
}

// Enable 启用店铺
func (s *Service) Enable(ctx context.Context, id uint) error {
	// 获取当前用户 ID
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 查询店铺
	shop, err := s.shopStore.GetByID(ctx, id)
	if err != nil {
		return errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	// 更新状态
	shop.Status = constants.StatusEnabled
	shop.Updater = currentUserID

	return s.shopStore.Update(ctx, shop)
}

// GetByID 获取店铺详情
func (s *Service) GetByID(ctx context.Context, id uint) (*model.Shop, error) {
	shop, err := s.shopStore.GetByID(ctx, id)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}
	return shop, nil
}

func (s *Service) ListShopResponses(ctx context.Context, req *dto.ShopListRequest) ([]*dto.ShopResponse, int64, error) {
	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.ShopName != "" {
		filters["shop_name"] = req.ShopName
	}
	if req.ShopCode != "" {
		filters["shop_code"] = req.ShopCode
	}
	if req.ParentID != nil {
		filters["parent_id"] = *req.ParentID
	}
	if req.Level != nil {
		filters["level"] = *req.Level
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}

	shops, total, err := s.shopStore.List(ctx, opts, filters)
	if err != nil {
		return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询店铺列表失败")
	}

	responses := make([]*dto.ShopResponse, 0, len(shops))
	for _, shop := range shops {
		responses = append(responses, &dto.ShopResponse{
			ID:           shop.ID,
			ShopName:     shop.ShopName,
			ShopCode:     shop.ShopCode,
			ParentID:     shop.ParentID,
			Level:        shop.Level,
			ContactName:  shop.ContactName,
			ContactPhone: shop.ContactPhone,
			Province:     shop.Province,
			City:         shop.City,
			District:     shop.District,
			Address:      shop.Address,
			Status:       shop.Status,
			StatusName:   constants.GetStatusName(shop.Status),
			CreatedAt:    shop.CreatedAt.Format("2006-01-02 15:04:05"),
			UpdatedAt:    shop.UpdatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return responses, total, nil
}

func (s *Service) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Shop, int64, error) {
	return s.shopStore.List(ctx, opts, filters)
}

// ListCascade 联级查询店铺，用于新增店铺或其他场景选择上级店铺
func (s *Service) ListCascade(ctx context.Context, req *dto.ShopCascadeRequest) ([]*dto.ShopCascadeItem, error) {
	shops, err := s.shopStore.ListForCascade(ctx, req.ShopName, req.ParentID)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询店铺失败")
	}

	if len(shops) == 0 {
		return []*dto.ShopCascadeItem{}, nil
	}

	ids := make([]uint, 0, len(shops))
	for _, shop := range shops {
		ids = append(ids, shop.ID)
	}

	childParentIDs, err := s.shopStore.GetParentIDsWithChildren(ctx, ids)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询下级店铺失败")
	}

	hasChildrenSet := make(map[uint]bool, len(childParentIDs))
	for _, pid := range childParentIDs {
		hasChildrenSet[pid] = true
	}

	result := make([]*dto.ShopCascadeItem, 0, len(shops))
	for _, shop := range shops {
		result = append(result, &dto.ShopCascadeItem{
			ID:          shop.ID,
			ShopName:    shop.ShopName,
			HasChildren: hasChildrenSet[shop.ID],
		})
	}

	return result, nil
}

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

	shop, err := s.shopStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeShopNotFound, "店铺不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取店铺失败")
	}

	accounts, err := s.accountStore.GetByShopID(ctx, shop.ID)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "查询店铺账号失败")
	}

	if len(accounts) > 0 {
		accountIDs := make([]uint, 0, len(accounts))
		for _, account := range accounts {
			accountIDs = append(accountIDs, account.ID)
		}
		if err := s.accountStore.BulkUpdateStatus(ctx, accountIDs, constants.StatusDisabled, currentUserID); err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "禁用店铺账号失败")
		}
	}

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

	return nil
}

// GetSubordinateShopIDs 获取下级店铺 ID 列表（包含自己）
func (s *Service) GetSubordinateShopIDs(ctx context.Context, shopID uint) ([]uint, error) {
	return s.shopStore.GetSubordinateShopIDs(ctx, shopID)
}
