package wecom

import (
	"context"
	"strings"
	"time"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
)

// MemberRepository 持久化企业微信应用可见成员快照。
type MemberRepository struct {
	db *gorm.DB
}

// NewMemberRepository 创建企业微信成员快照 Repository。
func NewMemberRepository(db *gorm.DB) *MemberRepository {
	return &MemberRepository{db: db}
}

// ReplaceVisible 原子替换指定应用当前可见成员，历史不可见成员仅标记为不可见。
func (r *MemberRepository) ReplaceVisible(ctx context.Context, applicationID uint, members []model.WeComMember, syncedAt time.Time) error {
	if r == nil || r.db == nil {
		return errors.New(errors.CodeDatabaseError, "企业微信成员存储未配置")
	}
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Model(&model.WeComMember{}).Where("application_id = ?", applicationID).
			Updates(map[string]any{"visible": false, "updated_at": syncedAt}).Error; err != nil {
			return err
		}
		if len(members) == 0 {
			return nil
		}
		return tx.Clauses(clause.OnConflict{
			Columns: []clause.Column{{Name: "application_id"}, {Name: "userid"}},
			DoUpdates: clause.Assignments(map[string]any{
				"corp_id": gorm.Expr("EXCLUDED.corp_id"), "name": gorm.Expr("EXCLUDED.name"),
				"department_ids": gorm.Expr("EXCLUDED.department_ids"), "visible": true,
				"synced_at": gorm.Expr("EXCLUDED.synced_at"), "updated_at": syncedAt,
			}),
		}).CreateInBatches(&members, constants.WeComMemberSyncBatchSize).Error
	})
	if err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "同步企业微信可见成员失败")
	}
	return nil
}

// ListVisible 分页查询指定应用当前可见成员。
func (r *MemberRepository) ListVisible(ctx context.Context, applicationID uint, page, pageSize int, keyword string) ([]model.WeComMember, int64, error) {
	query := r.db.WithContext(ctx).Model(&model.WeComMember{}).
		Joins("JOIN tb_wecom_application ON tb_wecom_application.id = tb_wecom_member.application_id AND tb_wecom_application.deleted_at IS NULL AND tb_wecom_application.status = ?", constants.StatusEnabled).
		Where("tb_wecom_member.application_id = ? AND tb_wecom_member.visible = ?", applicationID, true)
	keyword = strings.TrimSpace(keyword)
	if keyword != "" {
		query = query.Where("tb_wecom_member.name ILIKE ? OR tb_wecom_member.userid ILIKE ?", "%"+keyword+"%", "%"+keyword+"%")
	}
	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "统计企业微信可见成员失败")
	}
	var members []model.WeComMember
	if err := query.Select("tb_wecom_member.*").Order("tb_wecom_member.name ASC, tb_wecom_member.userid ASC").
		Offset((page - 1) * pageSize).Limit(pageSize).Find(&members).Error; err != nil {
		return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "查询企业微信可见成员失败")
	}
	return members, total, nil
}

// GetVisible 查询可用于账号绑定的应用可见成员。
func (r *MemberRepository) GetVisible(ctx context.Context, applicationID uint, userID string) (*model.WeComMember, error) {
	var member model.WeComMember
	if err := r.db.WithContext(ctx).Model(&model.WeComMember{}).
		Select("tb_wecom_member.*").
		Joins("JOIN tb_wecom_application ON tb_wecom_application.id = tb_wecom_member.application_id AND tb_wecom_application.deleted_at IS NULL AND tb_wecom_application.status = ?", constants.StatusEnabled).
		Where("tb_wecom_member.application_id = ? AND tb_wecom_member.userid = ? AND tb_wecom_member.visible = ?", applicationID, strings.ToLower(strings.TrimSpace(userID)), true).
		First(&member).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeInvalidParam, "所选成员不在企业微信应用可见范围内")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询企业微信可见成员失败")
	}
	return &member, nil
}
