package paymentaccount

import (
	"context"
	"encoding/json"
	"errors"
	"strings"

	"hfb_sys/backend/internal/model"
	"hfb_sys/backend/pkg/crypto"

	"gorm.io/datatypes"
	"gorm.io/gorm"
)

type Repository struct {
	db        *gorm.DB
	encryptor crypto.Encryptor
}

func NewRepository(db *gorm.DB, encryptor crypto.Encryptor) *Repository {
	if encryptor == nil {
		encryptor = &crypto.MockEncryptor{}
	}
	return &Repository{db: db, encryptor: encryptor}
}

func (r *Repository) List(ctx context.Context, userID uint64, page, pageSize int) (*PaginatedResult, error) {
	db := r.db.WithContext(ctx)
	var total int64
	if err := db.Model(&model.UserPaymentAccount{}).
		Where("user_id = ? AND status = ?", userID, "active").
		Count(&total).Error; err != nil {
		return nil, err
	}

	offset := (page - 1) * pageSize
	var accounts []model.UserPaymentAccount
	if err := db.Where("user_id = ? AND status = ?", userID, "active").
		Order("is_default DESC, created_at DESC").
		Offset(offset).Limit(pageSize).
		Find(&accounts).Error; err != nil {
		return nil, err
	}

	items := make([]PaymentAccountDTO, 0, len(accounts))
	for _, acc := range accounts {
		dto, err := r.toDTO(acc)
		if err != nil {
			continue
		}
		items = append(items, *dto)
	}

	return &PaginatedResult{
		Items:    items,
		Total:    total,
		Page:     page,
		PageSize: pageSize,
	}, nil
}

func (r *Repository) FindByID(ctx context.Context, userID, id uint64) (*PaymentAccountDTO, error) {
	var account model.UserPaymentAccount
	if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ? AND status = ?", id, userID, "active").
		First(&account).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrAccountNotFound
		}
		return nil, err
	}
	return r.toDTO(account)
}

func (r *Repository) Create(ctx context.Context, userID uint64, req CreatePaymentAccountRequest) (*PaymentAccountDTO, error) {
	db := r.db.WithContext(ctx)
	// 加密账号
	encryptedNo, err := r.encryptor.Encrypt(req.AccountNo)
	if err != nil {
		return nil, err
	}

	// 处理凭证URLs
	var certURLs datatypes.JSON
	if len(req.CertificateURLs) > 0 {
		certURLs, _ = json.Marshal(req.CertificateURLs)
	}

	// 如果是第一个账号，自动设为默认
	isDefault := false
	var count int64
	db.Model(&model.UserPaymentAccount{}).Where("user_id = ? AND status = ?", userID, "active").Count(&count)
	if count == 0 {
		isDefault = true
	}

	account := model.UserPaymentAccount{
		UserID:          userID,
		AccountType:     req.AccountType,
		AccountName:     req.AccountName,
		AccountNo:       encryptedNo,
		BankName:        req.BankName,
		BankBranch:      req.BankBranch,
		CertificateURLs: certURLs,
		IsDefault:       isDefault,
		Status:          "active",
	}

	if err := db.Create(&account).Error; err != nil {
		return nil, err
	}

	return r.FindByID(ctx, userID, account.ID)
}

func (r *Repository) Update(ctx context.Context, userID, id uint64, req UpdatePaymentAccountRequest) (*PaymentAccountDTO, error) {
	db := r.db.WithContext(ctx)
	var account model.UserPaymentAccount
	if err := db.Where("id = ? AND user_id = ? AND status = ?", id, userID, "active").
		First(&account).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrAccountNotFound
		}
		return nil, err
	}

	updates := make(map[string]interface{})

	if req.BankBranch != "" {
		updates["bank_branch"] = req.BankBranch
	}

	if len(req.CertificateURLs) > 0 {
		certURLs, _ := json.Marshal(req.CertificateURLs)
		updates["certificate_urls"] = certURLs
	}

	if req.IsDefault != nil && *req.IsDefault {
		// 先取消其他默认账号
		db.Model(&model.UserPaymentAccount{}).
			Where("user_id = ? AND id != ?", userID, id).
			Update("is_default", false)
		updates["is_default"] = true
	}

	if len(updates) > 0 {
		if err := db.Model(&account).Updates(updates).Error; err != nil {
			return nil, err
		}
	}

	return r.FindByID(ctx, userID, id)
}

func (r *Repository) Delete(ctx context.Context, userID, id uint64) error {
	db := r.db.WithContext(ctx)
	var account model.UserPaymentAccount
	if err := db.Where("id = ? AND user_id = ? AND status = ?", id, userID, "active").
		First(&account).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ErrAccountNotFound
		}
		return err
	}

	// 软删除
	return db.Model(&account).Update("status", "disabled").Error
}

func (r *Repository) SetDefault(ctx context.Context, userID, id uint64) error {
	// 验证账号存在
	var account model.UserPaymentAccount
	if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ? AND status = ?", id, userID, "active").
		First(&account).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ErrAccountNotFound
		}
		return err
	}

	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 取消其他默认账号
		if err := tx.Model(&model.UserPaymentAccount{}).
			Where("user_id = ? AND id != ?", userID, id).
			Update("is_default", false).Error; err != nil {
			return err
		}
		// 设置当前为默认
		return tx.Model(&account).Update("is_default", true).Error
	})
}

func (r *Repository) CountByUser(ctx context.Context, userID uint64) (int64, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&model.UserPaymentAccount{}).
		Where("user_id = ? AND status = ?", userID, "active").
		Count(&count).Error
	return count, err
}

func (r *Repository) ValidateRealname(ctx context.Context, userID uint64, accountName string) error {
	var user model.User
	db := r.db.WithContext(ctx)
	if err := db.First(&user, userID).Error; err != nil {
		return err
	}

	if user.RealnameStatus != "verified" {
		return ErrRealnameRequired
	}

	// 获取实名信息
	var realname model.UserRealname
	if err := db.Where("user_id = ? AND status = ?", userID, "verified").
		First(&realname).Error; err != nil {
		return ErrRealnameRequired
	}

	// 验证姓名匹配 - 使用加密字段进行精确匹配
	if realname.EncryptedName != "" {
		// 有加密字段，解密后精确匹配
		decryptedName, err := r.encryptor.Decrypt(realname.EncryptedName)
		if err != nil {
			// 解密失败，降级到前缀匹配
			return r.validateByMaskedName(realname.MaskedName, accountName)
		}
		// 精确匹配（去除空格）
		if strings.ReplaceAll(decryptedName, " ", "") != strings.ReplaceAll(accountName, " ", "") {
			return ErrAccountNameMismatch
		}
	} else {
		// 没有加密字段（旧数据），使用前缀匹配
		return r.validateByMaskedName(realname.MaskedName, accountName)
	}

	return nil
}

// 使用脱敏姓名进行前缀匹配（兼容旧数据）
func (r *Repository) validateByMaskedName(maskedName, accountName string) error {
	maskedName = strings.ReplaceAll(maskedName, " ", "")
	inputName := strings.ReplaceAll(accountName, " ", "")

	if strings.Contains(maskedName, "*") {
		// 提取非星号部分（通常是姓氏）
		prefix := strings.Split(maskedName, "*")[0]
		if prefix != "" && !strings.HasPrefix(inputName, prefix) {
			return ErrAccountNameMismatch
		}
	} else {
		// 完整匹配
		if maskedName != inputName {
			return ErrAccountNameMismatch
		}
	}
	return nil
}

func (r *Repository) toDTO(account model.UserPaymentAccount) (*PaymentAccountDTO, error) {
	// 解密账号并脱敏
	decrypted, err := r.encryptor.Decrypt(account.AccountNo)
	if err != nil {
		decrypted = account.AccountNo // 降级处理
	}
	maskedNo := maskAccountNo(decrypted, account.AccountType)

	// 解析凭证URLs
	var certURLs []string
	if account.CertificateURLs != nil {
		json.Unmarshal(account.CertificateURLs, &certURLs)
	}

	return &PaymentAccountDTO{
		ID:              account.ID,
		UserID:          account.UserID,
		AccountType:     account.AccountType,
		AccountName:     account.AccountName,
		AccountNo:       maskedNo,
		BankName:        account.BankName,
		BankBranch:      account.BankBranch,
		CertificateURLs: certURLs,
		IsDefault:       account.IsDefault,
		Status:          account.Status,
		CreatedAt:       account.CreatedAt,
		UpdatedAt:       account.UpdatedAt,
	}, nil
}

// 账号脱敏
func maskAccountNo(accountNo, accountType string) string {
	length := len(accountNo)
	if length <= 4 {
		return accountNo
	}

	switch accountType {
	case "alipay", "wechat":
		// 手机号或邮箱
		if length == 11 {
			return accountNo[:3] + "****" + accountNo[7:]
		}
		return accountNo[:2] + "****" + accountNo[length-2:]
	case "bank":
		// 银行卡号
		if length > 8 {
			return accountNo[:4] + "****" + accountNo[length-4:]
		}
		return accountNo[:2] + "****" + accountNo[length-2:]
	}
	return accountNo
}

// 获取解密后的账号（仅供内部使用，如提现申请时）
func (r *Repository) GetDecryptedAccountNo(ctx context.Context, userID, id uint64) (string, error) {
	var account model.UserPaymentAccount
	if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ?", id, userID).First(&account).Error; err != nil {
		return "", err
	}
	return r.encryptor.Decrypt(account.AccountNo)
}
