package user_usecase

import (
	_const "chonho/const"
	"chonho/internal/api-v1/entity"
	"chonho/internal/api-v1/repository/address_repository"
	"chonho/internal/api-v1/repository/fmc_repository"
	"chonho/internal/api-v1/repository/user_repository"
	_error "chonho/pkg/c_error"
	"chonho/pkg/model"
	"chonho/pkg/sha"
	"context"
	"gorm.io/gorm"
)

type UseCase interface {
	UpdateAddress(userId int64, info entity.UpdateShippingAddressRequest) (*entity.UserShippingAddress, error)
	ChangePassword(userId int64, newPassword string, ctx context.Context) error
	AddFCMRegistrationToken(userId int64, token, deviceId string) error
}

type useCase struct {
	addressRepo address_repository.AddressRepository
	userRepo    user_repository.UserRepository
	fcmRepo     fmc_repository.FCMRepository
}

func NewUserUseCase(addressRepo address_repository.AddressRepository, userRepo user_repository.UserRepository, fcmRepo fmc_repository.FCMRepository) UseCase {
	return &useCase{
		addressRepo: addressRepo,
		userRepo:    userRepo,
		fcmRepo:     fcmRepo,
	}
}

func (uc *useCase) UpdateAddress(userId int64, info entity.UpdateShippingAddressRequest) (*entity.UserShippingAddress, error) {

	isMain := true
	address, err := uc.addressRepo.First(address_repository.AddressFilter{
		UserId:        userId,
		IsMainAddress: &isMain,
	})
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}

	if address == nil {
		address = &model.UserShippingAddress{
			IsMainAddress: true,
			UserID:        userId,
		}
	}

	address.ApartmentId = info.ApartmentId
	address.ApartmentHouseNumber = info.ApartmentHouseNumber
	address.ReceiverName = info.ReceiverName
	address.ReceiverPhone = info.ReceiverPhone

	if err = uc.addressRepo.Save(address); err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}

	return &entity.UserShippingAddress{
		Id:                   address.Id,
		ReceiverName:         address.ReceiverName,
		ReceiverPhone:        address.ReceiverPhone,
		ApartmentHouseNumber: address.ApartmentHouseNumber,
		ApartmentId:          address.ApartmentId,
	}, nil
}

func (uc *useCase) ChangePassword(userId int64, newPassword string, ctx context.Context) error {
	user, err := uc.userRepo.First(user_repository.UserFilter{
		UserID: userId,
	})
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return _error.New(_const.UserNotFound, "user not found")
		}
		return _error.New(_const.InternalServerErr, err.Error())
	}
	user.Password = sha.Decode(newPassword, user.Salt)
	err = uc.userRepo.Save(user)
	if err != nil {
		return _error.New(_const.InternalServerErr, err.Error())
	}
	return nil
}

func (uc *useCase) AddFCMRegistrationToken(userId int64, token, deviceId string) error {

	fcmToken, _ := uc.fcmRepo.FirstToken(fmc_repository.TokenFilter{
		DeviceId: deviceId,
	})

	if fcmToken == nil {
		fcmToken = &model.FcmToken{
			DeviceId: deviceId,
		}
	}

	fcmToken.RegistrationToken = token
	fcmToken.UserId = userId

	return uc.fcmRepo.Save(fcmToken)
}
