package repository

import (
	"common/db/mysql"
	"common/db/redis"
	"context"
	"fmt"
	"time"
	"user/internal/dao/model"
	"user/internal/dao/query"
)

var (
	cacheBySn    = "c:user:s:%v"
	cacheByPhone = "c:user:p:%v"
)

type UserDao struct {
	ctx   context.Context
	query *query.Query
	cache *redis.CacheClient
}

func NewUserDao(ctx context.Context, cache ...*redis.CacheClient) *UserDao {
	dao := &UserDao{
		ctx:   ctx,
		query: query.Use(mysql.GetDB("user_db")),
	}
	if len(cache) > 0 {
		dao.cache = cache[0]
	}
	return dao
}

func (d *UserDao) Create(user *model.User) error {
	err := d.query.User.WithContext(d.ctx).
		Create(user)
	return err
}

func (d *UserDao) Updates(user *model.User) error {
	info, _ := d.query.User.WithContext(d.ctx).
		Where(d.query.User.ID.Eq(user.ID)).
		Updates(user)
	if info.RowsAffected > 0 {
		if d.cache != nil {
			d.cache.Del(d.ctx, fmt.Sprintf(cacheBySn, user.Sn))
			d.cache.Del(d.ctx, fmt.Sprintf(cacheByPhone, user.Phone))
		}
	}
	return info.Error
}

func (d *UserDao) FindBySn(sn int64) (*model.User, error) {
	if d.cache != nil {
		var user model.User
		if ok := d.cache.Get(d.ctx, fmt.Sprintf(cacheBySn, sn), &user); ok {
			return &user, nil
		}
	}
	first, err := d.query.User.WithContext(d.ctx).
		Where(d.query.User.Sn.Eq(sn)).
		First()
	if err != nil {
		return nil, err
	}
	if d.cache != nil {
		d.cache.Set(d.ctx, fmt.Sprintf(cacheBySn, sn), first, 5*time.Minute)
	}
	return first, nil
}

func (d *UserDao) FindByPhone(phone string) (*model.User, error) {
	if d.cache != nil {
		var user model.User
		if ok := d.cache.Get(d.ctx, fmt.Sprintf(cacheByPhone, phone), &user); ok {
			return &user, nil
		}
	}
	first, err := d.query.User.WithContext(d.ctx).
		Where(d.query.User.Phone.Eq(phone)).
		First()
	if err != nil {
		return nil, err
	}
	if d.cache != nil {
		d.cache.Set(d.ctx, fmt.Sprintf(cacheByPhone, phone), first, 5*time.Minute)
	}
	return first, nil
}
