package service

import (
	"context"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"strings"

	"bdqr-server/app/main/api/internal/config"
	"bdqr-server/app/main/model"
	"bdqr-server/common/xerr"
	"bdqr-server/pkg/lzkit/crypto"
	"bdqr-server/pkg/lzkit/lzUtils"

	"github.com/google/uuid"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

// WhitelistService 白名单领域服务，集中处理白名单相关的业务逻辑
type WhitelistService struct {
	config                    config.Config
	UserFeatureWhitelistModel model.UserFeatureWhitelistModel
	WhitelistOrderModel       model.WhitelistOrderModel
	WhitelistOrderItemModel   model.WhitelistOrderItemModel
	QueryModel                model.QueryModel
	FeatureModel              model.FeatureModel
}

// NewWhitelistService 创建白名单服务
func NewWhitelistService(
	c config.Config,
	userFeatureWhitelistModel model.UserFeatureWhitelistModel,
	whitelistOrderModel model.WhitelistOrderModel,
	whitelistOrderItemModel model.WhitelistOrderItemModel,
	queryModel model.QueryModel,
	featureModel model.FeatureModel,
) *WhitelistService {
	return &WhitelistService{
		config:                    c,
		UserFeatureWhitelistModel: userFeatureWhitelistModel,
		WhitelistOrderModel:       whitelistOrderModel,
		WhitelistOrderItemModel:   whitelistOrderItemModel,
		QueryModel:                queryModel,
		FeatureModel:              featureModel,
	}
}

// EnsureFreeWhitelist 免费下架：如果还没有生效白名单，则创建一条免费白名单记录
func (s *WhitelistService) EnsureFreeWhitelist(
	ctx context.Context,
	session sqlx.Session,
	idCard string,
	feature *model.Feature,
	userId string,
	orderId string,
) error {
	// 检查是否已存在生效白名单
	builder := s.UserFeatureWhitelistModel.SelectBuilder().
		Where("id_card = ? AND feature_id = ?", idCard, feature.Id)
	records, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
	if err != nil {
		return errors.Wrap(err, "查询白名单记录失败")
	}
	for _, r := range records {
		if r.Status == 1 {
			// 已经下架，直接返回
			return nil
		}
	}

	wl := &model.UserFeatureWhitelist{
		Id:               uuid.NewString(),
		IdCard:           idCard,
		FeatureId:        feature.Id,
		FeatureApiId:     feature.ApiId,
		UserId:           userId,
		OrderId:          lzUtils.StringToNullString(orderId),
		WhitelistOrderId: lzUtils.StringToNullString(""),
		Amount:           0,
		Status:           1,
	}

	_, err = s.UserFeatureWhitelistModel.Insert(ctx, session, wl)
	if err != nil {
		return errors.Wrap(err, "创建免费白名单记录失败")
	}
	return nil
}

// CreateWhitelistByPaidOrder 根据已支付的白名单订单，创建对应的白名单记录
func (s *WhitelistService) CreateWhitelistByPaidOrder(
	ctx context.Context,
	session sqlx.Session,
	order *model.Order,
	whitelistOrder *model.WhitelistOrder,
) error {
	if whitelistOrder.Status != 2 {
		// 只处理已支付状态
		return nil
	}

	itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
		Where("order_id = ?", whitelistOrder.Id)
	items, err := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
	if err != nil {
		return errors.Wrap(err, "查询白名单订单明细失败")
	}

	for _, item := range items {
		wl := &model.UserFeatureWhitelist{
			Id:               uuid.NewString(),
			IdCard:           whitelistOrder.IdCard,
			FeatureId:        item.FeatureId,
			FeatureApiId:     item.FeatureApiId,
			UserId:           whitelistOrder.UserId,
			OrderId:          lzUtils.StringToNullString(order.Id),
			WhitelistOrderId: lzUtils.StringToNullString(whitelistOrder.Id),
			Amount:           item.Price,
			Status:           1,
		}
		if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
			return errors.Wrap(err, "创建白名单记录失败")
		}
	}

	return nil
}

// GetWhitelistedFeatureApisByIdCard 获取某个身份证号已下架的 feature_api_id 集合
func (s *WhitelistService) GetWhitelistedFeatureApisByIdCard(
	ctx context.Context,
	idCard string,
) (map[string]bool, error) {
	result := make(map[string]bool)
	if s == nil {
		return result, nil
	}
	if idCard == "" {
		return result, nil
	}

	builder := s.UserFeatureWhitelistModel.SelectBuilder().
		Where("id_card = ? AND status = ?", idCard, 1)
	list, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, errors.Wrap(err, "查询白名单失败")
	}

	for _, wl := range list {
		result[wl.FeatureApiId] = true
	}
	return result, nil
}

// CheckWhitelistExists 检查指定身份证号和模块是否已有生效的白名单记录
func (s *WhitelistService) CheckWhitelistExists(
	ctx context.Context,
	idCard string,
	featureId string,
) (bool, error) {
	if idCard == "" || featureId == "" {
		return false, nil
	}

	builder := s.UserFeatureWhitelistModel.SelectBuilder().
		Where("id_card = ? AND feature_id = ? AND status = ?", idCard, featureId, 1)
	list, err := s.UserFeatureWhitelistModel.FindAll(ctx, builder, "")
	if err != nil {
		return false, errors.Wrap(err, "查询白名单记录失败")
	}

	return len(list) > 0, nil
}

// ProcessOfflineFeature 统一下架处理：处理免费下架或检查付费下架
// 返回：needPay(是否需要支付), amount(金额), whitelistCreated(是否已创建白名单)
func (s *WhitelistService) ProcessOfflineFeature(
	ctx context.Context,
	session sqlx.Session,
	idCard string,
	featureApiId string,
	userId string,
	orderId string,
) (needPay bool, amount float64, whitelistCreated bool, err error) {
	// 1. 提取主模块ID并查询feature信息
	mainApiId := s.extractMainApiId(featureApiId)
	feature, err := s.getFeatureByApiId(ctx, mainApiId)
	if err != nil {
		return false, 0, false, err
	}

	// 2. 不支持下架的模块：whitelist_price < 0 表示该模块不开放下架功能
	if feature.WhitelistPrice < 0 {
		return false, 0, false, errors.Wrapf(xerr.NewErrMsg("该模块不支持下架"), "")
	}

	// 3. 检查是否已有白名单
	exists, err := s.CheckWhitelistExists(ctx, idCard, feature.Id)
	if err != nil {
		return false, 0, false, err
	}
	if exists {
		// 已有白名单，直接返回成功
		return false, 0, true, nil
	}

	price := feature.WhitelistPrice

	// 4. 免费下架：直接创建白名单记录（whitelist_price = 0）
	if price <= 0 {
		if err := s.EnsureFreeWhitelist(ctx, session, idCard, feature, userId, orderId); err != nil {
			return false, 0, false, err
		}
		return false, 0, true, nil
	}

	// 5. 付费下架：检查是否已有支付成功的订单
	paidOrderId, err := s.findPaidWhitelistOrder(ctx, userId, idCard, feature.Id)
	if err != nil {
		return false, 0, false, err
	}

	// 6. 如果已有支付成功订单，补创建白名单记录
	if paidOrderId != "" {
		if err := s.createWhitelistFromPaidOrder(ctx, session, idCard, feature, userId, orderId, paidOrderId, price); err != nil {
			return false, 0, false, err
		}
		return false, price, true, nil
	}

	// 7. 需要支付
	return true, price, false, nil
}

// extractMainApiId 提取主模块ID（去掉下划线后的部分）
func (s *WhitelistService) extractMainApiId(featureApiId string) string {
	if idx := strings.Index(featureApiId, "_"); idx > 0 {
		return featureApiId[:idx]
	}
	return featureApiId
}

// getFeatureByApiId 根据API ID查询feature信息
func (s *WhitelistService) getFeatureByApiId(ctx context.Context, apiId string) (*model.Feature, error) {
	feature, err := s.FeatureModel.FindOneByApiId(ctx, apiId)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrap(err, "模块不存在")
		}
		return nil, errors.Wrap(err, "查询模块信息失败")
	}
	return feature, nil
}

// findPaidWhitelistOrder 查找已支付的白名单订单中是否包含指定feature
// 返回：paidOrderId（如果找到已支付订单），error
func (s *WhitelistService) findPaidWhitelistOrder(
	ctx context.Context,
	userId string,
	idCard string,
	featureId string,
) (string, error) {
	orderBuilder := s.WhitelistOrderModel.SelectBuilder().
		Where("user_id = ? AND id_card = ? AND status = ?", userId, idCard, 2) // 2表示已支付
	orders, err := s.WhitelistOrderModel.FindAll(ctx, orderBuilder, "")
	if err != nil {
		return "", errors.Wrap(err, "查询白名单订单失败")
	}

	// 查找已支付订单中是否包含该feature
	for _, order := range orders {
		itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
			Where("order_id = ? AND feature_id = ?", order.Id, featureId)
		items, itemErr := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
		if itemErr != nil {
			return "", errors.Wrap(itemErr, "查询白名单订单明细失败")
		}
		if len(items) > 0 {
			return order.Id, nil
		}
	}

	return "", nil
}

// createWhitelistFromPaidOrder 根据已支付订单创建白名单记录
func (s *WhitelistService) createWhitelistFromPaidOrder(
	ctx context.Context,
	session sqlx.Session,
	idCard string,
	feature *model.Feature,
	userId string,
	orderId string,
	paidOrderId string,
	price float64,
) error {
	wl := &model.UserFeatureWhitelist{
		Id:               uuid.NewString(),
		IdCard:           idCard,
		FeatureId:        feature.Id,
		FeatureApiId:     feature.ApiId,
		UserId:           userId,
		OrderId:          lzUtils.StringToNullString(orderId),
		WhitelistOrderId: lzUtils.StringToNullString(paidOrderId),
		Amount:           price,
		Status:           1, // 生效
	}
	if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
		return errors.Wrap(err, "根据已支付订单创建白名单记录失败")
	}
	return nil
}

// DeleteFeatureFromQueryData 从报告数据中删除指定模块的数据
// queryId: 查询记录ID（Query表的ID）
// featureApiId: 要删除的模块API标识
func (s *WhitelistService) DeleteFeatureFromQueryData(
	ctx context.Context,
	session sqlx.Session,
	queryId string,
	featureApiId string,
) error {
	// 1. 获取查询记录
	queryModel, err := s.getQueryModel(ctx, queryId)
	if err != nil {
		return err
	}
	if queryModel == nil {
		// 报告不存在或数据为空，直接返回成功
		return nil
	}

	// 2. 解密并解析报告数据
	mainApiId := s.extractMainApiId(featureApiId)
	dataArray, key, err := s.decryptQueryData(queryModel)
	if err != nil {
		return err
	}

	// 3. 清空对应模块的数据（将 data 字段设置为 null）
	modifiedArray, hasModified := s.clearFeatureData(dataArray, mainApiId)
	if !hasModified {
		logx.Infof("删除报告数据：查询记录 %s 中未找到模块 %s 的数据，跳过删除", queryId, featureApiId)
		return nil
	}

	// 4. 重新加密并更新数据库
	if err := s.updateQueryData(ctx, session, queryModel, modifiedArray, key); err != nil {
		return err
	}

	logx.Infof("删除报告数据成功：查询记录 %s，模块 %s，已将对应模块的 data 字段设置为 null", queryId, featureApiId)
	return nil
}

// getQueryModel 获取查询记录，如果不存在或数据为空则返回nil
func (s *WhitelistService) getQueryModel(ctx context.Context, queryId string) (*model.Query, error) {
	queryModel, err := s.QueryModel.FindOne(ctx, queryId)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			logx.Infof("删除报告数据：查询记录 %s 不存在，跳过删除", queryId)
			return nil, nil
		}
		return nil, errors.Wrap(err, "查询报告记录失败")
	}

	// 如果报告数据为空，直接返回
	if !queryModel.QueryData.Valid || queryModel.QueryData.String == "" {
		logx.Infof("删除报告数据：查询记录 %s 对应的报告数据为空，跳过删除", queryId)
		return nil, nil
	}

	return queryModel, nil
}

// decryptQueryData 解密并解析报告数据
func (s *WhitelistService) decryptQueryData(queryModel *model.Query) ([]map[string]interface{}, []byte, error) {
	// 获取加密密钥
	secretKey := s.config.Encrypt.SecretKey
	key, decodeErr := hex.DecodeString(secretKey)
	if decodeErr != nil {
		return nil, nil, errors.Wrap(decodeErr, "获取AES密钥失败")
	}

	// 解密报告数据
	decryptedData, decryptErr := crypto.AesDecrypt(queryModel.QueryData.String, key)
	if decryptErr != nil {
		return nil, nil, errors.Wrap(decryptErr, "解密报告数据失败")
	}

	// 解析JSON数组
	var dataArray []map[string]interface{}
	unmarshalErr := json.Unmarshal(decryptedData, &dataArray)
	if unmarshalErr != nil {
		return nil, nil, errors.Wrap(unmarshalErr, "解析报告数据失败")
	}

	return dataArray, key, nil
}

// clearFeatureData 清空指定模块的数据（将 data 字段设置为 null）
// 返回修改后的数组和是否进行了修改
func (s *WhitelistService) clearFeatureData(dataArray []map[string]interface{}, mainApiId string) ([]map[string]interface{}, bool) {
	modifiedArray := make([]map[string]interface{}, 0, len(dataArray))
	hasModified := false

	for _, item := range dataArray {
		// 深拷贝 item，避免修改原数据
		newItem := make(map[string]interface{})
		for k, v := range item {
			newItem[k] = v
		}

		apiID, ok := item["apiID"].(string)
		if !ok {
			// 如果apiID不存在或类型不对，保留原样
			modifiedArray = append(modifiedArray, newItem)
			continue
		}

		// 提取主模块ID进行比较
		itemMainApiId := s.extractMainApiId(apiID)

		// 如果主模块ID匹配，将 data 字段设置为 null
		if itemMainApiId == mainApiId {
			newItem["data"] = nil
			hasModified = true
		}

		modifiedArray = append(modifiedArray, newItem)
	}

	return modifiedArray, hasModified
}

// updateQueryData 重新加密并更新数据库
func (s *WhitelistService) updateQueryData(
	ctx context.Context,
	session sqlx.Session,
	queryModel *model.Query,
	filteredArray []map[string]interface{},
	key []byte,
) error {
	// 重新序列化
	filteredBytes, marshalErr := json.Marshal(filteredArray)
	if marshalErr != nil {
		return errors.Wrap(marshalErr, "序列化过滤后的报告数据失败")
	}

	// 重新加密
	encryptedData, encryptErr := crypto.AesEncrypt(filteredBytes, key)
	if encryptErr != nil {
		return errors.Wrap(encryptErr, "加密过滤后的报告数据失败")
	}

	// 更新数据库
	queryModel.QueryData = sql.NullString{
		String: encryptedData,
		Valid:  true,
	}
	updateErr := s.QueryModel.UpdateWithVersion(ctx, session, queryModel)
	if updateErr != nil {
		return errors.Wrap(updateErr, "更新报告数据失败")
	}

	return nil
}

// CheckQueryDataContainsFeature 检查报告数据中是否包含指定的模块
// 返回 true 表示包含该模块，false 表示不包含（已删除）
func (s *WhitelistService) CheckQueryDataContainsFeature(
	ctx context.Context,
	queryId string,
	featureApiId string,
) (bool, error) {
	// 1. 获取查询记录
	queryModel, err := s.getQueryModel(ctx, queryId)
	if err != nil {
		return false, err
	}
	if queryModel == nil {
		// 报告不存在，认为数据已删除
		return false, nil
	}

	// 2. 解密并解析报告数据
	mainApiId := s.extractMainApiId(featureApiId)
	dataArray, _, err := s.decryptQueryData(queryModel)
	if err != nil {
		return false, err
	}

	// 3. 检查数据中是否包含该模块（且 data 不为 null）
	for _, item := range dataArray {
		apiID, ok := item["apiID"].(string)
		if !ok {
			continue
		}
		// 提取主模块ID进行比较
		itemMainApiId := s.extractMainApiId(apiID)
		if itemMainApiId == mainApiId {
			// 找到了该模块，检查 data 字段
			dataValue, exists := item["data"]
			if !exists || dataValue == nil {
				// data 字段不存在或为 null，认为数据已删除
				return false, nil
			}
			// data 字段存在且不为 null，认为数据存在
			return true, nil
		}
	}

	// 未找到该模块的数据，说明已删除
	return false, nil
}

// ProcessPaidWhitelistOrder 处理已支付的白名单订单：创建白名单记录并删除报告数据
// order: 支付订单（Order表）
// whitelistOrder: 白名单订单（WhitelistOrder表）
func (s *WhitelistService) ProcessPaidWhitelistOrder(
	ctx context.Context,
	session sqlx.Session,
	order *model.Order,
	whitelistOrder *model.WhitelistOrder,
) error {
	if whitelistOrder.Status != 2 {
		// 只处理已支付状态
		return nil
	}

	// 查询订单明细
	itemBuilder := s.WhitelistOrderItemModel.SelectBuilder().
		Where("order_id = ?", whitelistOrder.Id)
	items, err := s.WhitelistOrderItemModel.FindAll(ctx, itemBuilder, "")
	if err != nil {
		return errors.Wrap(err, "查询白名单订单明细失败")
	}

	// 为每个明细创建白名单记录并删除报告数据
	for _, item := range items {
		// 创建白名单记录
		wl := &model.UserFeatureWhitelist{
			Id:               uuid.NewString(),
			IdCard:           whitelistOrder.IdCard,
			FeatureId:        item.FeatureId,
			FeatureApiId:     item.FeatureApiId,
			UserId:           whitelistOrder.UserId,
			OrderId:          lzUtils.StringToNullString(""), // 查询订单ID，如果有的话会在后续步骤中设置
			WhitelistOrderId: lzUtils.StringToNullString(whitelistOrder.Id),
			Amount:           item.Price,
			Status:           1, // 生效
		}
		if _, err := s.UserFeatureWhitelistModel.Insert(ctx, session, wl); err != nil {
			return errors.Wrap(err, "创建白名单记录失败")
		}

		// 尝试删除报告数据
		// 注意：由于支付回调时可能不知道具体的查询订单ID，这里先尝试根据 id_card 查找
		// 如果找不到对应的报告，就跳过删除步骤（不影响主流程）
		// 实际的报告数据删除应该在 OfflineFeature 接口中完成（如果提供了 orderId）
		// 这里暂时不删除，因为无法确定是哪个具体的查询订单
		logx.Infof("白名单订单支付成功：订单 %s，模块 %s，已创建白名单记录。如需删除报告数据，请在 OfflineFeature 接口中提供查询订单ID", whitelistOrder.OrderNo, item.FeatureApiId)
	}

	return nil
}

