package postgres

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/store"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/logger"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/bytedance/sonic"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// ShopStore 店铺数据访问层
type ShopStore struct {
	db    *gorm.DB
	redis *redis.Client
}

// NewShopStore 创建店铺 Store
func NewShopStore(db *gorm.DB, redis *redis.Client) *ShopStore {
	return &ShopStore{
		db:    db,
		redis: redis,
	}
}

// Create 创建店铺
func (s *ShopStore) Create(ctx context.Context, shop *model.Shop) error {
	return s.db.WithContext(ctx).Create(shop).Error
}

// GetByID 根据 ID 获取店铺
func (s *ShopStore) GetByID(ctx context.Context, id uint) (*model.Shop, error) {
	var shop model.Shop
	if err := s.db.WithContext(ctx).First(&shop, id).Error; err != nil {
		return nil, err
	}
	return &shop, nil
}

// GetByCode 根据店铺编号获取店铺
func (s *ShopStore) GetByCode(ctx context.Context, code string) (*model.Shop, error) {
	var shop model.Shop
	if err := s.db.WithContext(ctx).Where("shop_code = ?", code).First(&shop).Error; err != nil {
		return nil, err
	}
	return &shop, nil
}

// Update 更新店铺
func (s *ShopStore) Update(ctx context.Context, shop *model.Shop) error {
	// 更新后清除缓存
	if err := s.db.WithContext(ctx).Save(shop).Error; err != nil {
		return err
	}

	// 清除该店铺的下级缓存
	cacheKey := constants.RedisShopSubordinatesKey(shop.ID)
	_ = s.redis.Del(ctx, cacheKey).Err()

	// 如果有上级,也清除上级的缓存
	if shop.ParentID != nil {
		parentCacheKey := constants.RedisShopSubordinatesKey(*shop.ParentID)
		_ = s.redis.Del(ctx, parentCacheKey).Err()
	}

	return nil
}

// Delete 软删除店铺
func (s *ShopStore) Delete(ctx context.Context, id uint) error {
	// 删除前先查询店铺信息
	shop, err := s.GetByID(ctx, id)
	if err != nil {
		return err
	}

	// 软删除
	if err := s.db.WithContext(ctx).Delete(&model.Shop{}, id).Error; err != nil {
		return err
	}

	// 清除缓存
	cacheKey := constants.RedisShopSubordinatesKey(id)
	_ = s.redis.Del(ctx, cacheKey).Err()

	// 如果有上级,也清除上级的缓存
	if shop.ParentID != nil {
		parentCacheKey := constants.RedisShopSubordinatesKey(*shop.ParentID)
		_ = s.redis.Del(ctx, parentCacheKey).Err()
	}

	return nil
}

// List 查询店铺列表
func (s *ShopStore) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Shop, int64, error) {
	var shops []*model.Shop
	var total int64

	query := s.db.WithContext(ctx).Model(&model.Shop{})
	// 应用数据权限过滤：代理用户只能看到自己店铺及下级店铺
	query = middleware.ApplyShopIDFilter(ctx, query)

	// 应用过滤条件
	if shopName, ok := filters["shop_name"].(string); ok && shopName != "" {
		query = query.Where("shop_name LIKE ?", "%"+shopName+"%")
	}
	if shopCode, ok := filters["shop_code"].(string); ok && shopCode != "" {
		query = query.Where("shop_code = ?", shopCode)
	}
	if contactPhone, ok := filters["contact_phone"].(string); ok && contactPhone != "" {
		query = query.Where("contact_phone = ?", contactPhone)
	}
	if parentID, ok := filters["parent_id"].(uint); ok {
		query = query.Where("parent_id = ?", parentID)
	}
	if level, ok := filters["level"].(int); ok {
		query = query.Where("level = ?", level)
	}
	if status, ok := filters["status"].(int); ok {
		query = query.Where("status = ?", status)
	}

	// 计算总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页
	if opts == nil {
		opts = &store.QueryOptions{
			Page:     1,
			PageSize: constants.DefaultPageSize,
		}
	}
	offset := (opts.Page - 1) * opts.PageSize
	query = query.Offset(offset).Limit(opts.PageSize)

	// 排序
	if opts.OrderBy != "" {
		query = query.Order(opts.OrderBy)
	} else {
		query = query.Order("created_at DESC")
	}

	// 查询
	if err := query.Find(&shops).Error; err != nil {
		return nil, 0, err
	}

	return shops, total, nil
}

// GetSubordinateShopIDs 递归查询下级店铺 ID（包含自己）
// 使用 Redis 缓存,缓存时间 30 分钟
func (s *ShopStore) GetSubordinateShopIDs(ctx context.Context, shopID uint) ([]uint, error) {
	// 尝试从缓存获取
	cacheKey := constants.RedisShopSubordinatesKey(shopID)
	cached, err := s.redis.Get(ctx, cacheKey).Result()
	if err == nil && cached != "" {
		var ids []uint
		if err := sonic.UnmarshalString(cached, &ids); err == nil {
			return ids, nil
		}
	}

	// 缓存未命中,递归查询数据库
	ids := []uint{shopID}
	if err := s.recursiveQuerySubordinates(ctx, shopID, &ids); err != nil {
		return nil, err
	}

	// 写入缓存
	if data, err := sonic.MarshalString(ids); err == nil {
		_ = s.redis.Set(ctx, cacheKey, data, 30*time.Minute).Err()
	}

	return ids, nil
}

// recursiveQuerySubordinates 递归查询下级店铺
func (s *ShopStore) recursiveQuerySubordinates(ctx context.Context, parentID uint, result *[]uint) error {
	var children []model.Shop
	if err := s.db.WithContext(ctx).
		Where("parent_id = ?", parentID).
		Find(&children).Error; err != nil {
		return err
	}

	for _, child := range children {
		*result = append(*result, child.ID)
		if err := s.recursiveQuerySubordinates(ctx, child.ID, result); err != nil {
			return err
		}
	}

	return nil
}

// GetByParentID 根据上级店铺 ID 查询直接下级店铺列表
func (s *ShopStore) GetByParentID(ctx context.Context, parentID uint) ([]*model.Shop, error) {
	var shops []*model.Shop
	if err := s.db.WithContext(ctx).Where("parent_id = ?", parentID).Find(&shops).Error; err != nil {
		return nil, err
	}
	return shops, nil
}

// GetByIDs 批量查询店铺
func (s *ShopStore) GetByIDs(ctx context.Context, ids []uint) ([]*model.Shop, error) {
	if len(ids) == 0 {
		return []*model.Shop{}, nil
	}
	var shops []*model.Shop
	query := s.db.WithContext(ctx).Where("id IN ?", ids)
	// 应用数据权限过滤：代理用户只能看到自己店铺及下级店铺
	subordinateShopIDs := middleware.GetSubordinateShopIDs(ctx)
	logger.GetAppLogger().Debug("GetByIDs 数据权限过滤",
		zap.Uints("requested_ids", ids),
		zap.Any("subordinate_shop_ids", subordinateShopIDs),
		zap.Int("user_type", middleware.GetUserTypeFromContext(ctx)))
	query = middleware.ApplyShopIDFilter(ctx, query)
	if err := query.Find(&shops).Error; err != nil {
		return nil, err
	}
	return shops, nil
}

// ListForCascade 联级查询店铺（支持按名称模糊查询、按上级ID过滤和排除自身）
func (s *ShopStore) ListForCascade(ctx context.Context, shopName string, parentID *uint, excludeSelf bool) ([]*model.Shop, error) {
	query := s.db.WithContext(ctx).Model(&model.Shop{})
	query = middleware.ApplyShopIDFilter(ctx, query)
	currentShopID := middleware.GetShopIDFromContext(ctx)

	if parentID != nil {
		query = query.Where("parent_id = ?", *parentID)
	} else if middleware.GetUserTypeFromContext(ctx) == constants.UserTypeAgent {
		if currentShopID == 0 {
			query = query.Where("1 = 0")
		} else if excludeSelf {
			// 排除自身时，代理账号的级联根节点从自身下级开始。
			query = query.Where("parent_id = ?", currentShopID)
		} else {
			// 代理账号的级联根节点是自己的店铺，避免默认根查询落到平台顶级店铺。
			query = query.Where("id = ?", currentShopID)
		}
	} else {
		query = query.Where("parent_id IS NULL")
	}

	if excludeSelf && currentShopID > 0 {
		query = query.Where("id <> ?", currentShopID)
	}

	if shopName != "" {
		query = query.Where("shop_name LIKE ?", "%"+shopName+"%")
	}

	var shops []*model.Shop
	if err := query.Order("created_at DESC").Find(&shops).Error; err != nil {
		return nil, err
	}
	return shops, nil
}

// GetParentIDsWithChildren 查询指定 ID 列表中哪些店铺有下级（返回作为上级的店铺ID集合）
func (s *ShopStore) GetParentIDsWithChildren(ctx context.Context, ids []uint) ([]uint, error) {
	if len(ids) == 0 {
		return []uint{}, nil
	}
	var parentIDs []uint
	if err := s.db.WithContext(ctx).Model(&model.Shop{}).
		Distinct("parent_id").
		Where("parent_id IN ?", ids).
		Pluck("parent_id", &parentIDs).Error; err != nil {
		return nil, err
	}
	return parentIDs, nil
}
