package service

import (
	"bpmsapi/dto"
	"bpmsapi/entity"
	"bpmsapi/repository"
	"bpmsapi/util"
	"database/sql"
	"fmt"
)

// It defines an interface named "Usecase" that specifies the methods a service should implement.
// Each method takes specific input parameters and returns an entity.CustomResponse object
type Usecase interface {
	AuthenticateCustomerService(mobno string) entity.CustomResponse //input & response(o/p)
	VerifyOTPCustomerService(mobno string, otp int64) entity.CustomResponse
	AuthenticateAdminService(mobno string) entity.CustomResponse
	InsertCustomerService(input entity.Signupuser) entity.CustomResponse
}

type AuthenticateService struct {
	userRepository   *repository.UserRepository
	notification     *repository.NotificationRepository
	otpRepository    *repository.OTPRepository
	adminRepository  *repository.AdminRepository
	configRepository *repository.ConfigRepository
}

// auth-jwt
func AuthenticateServiceInit(notification *repository.NotificationRepository, userRepository *repository.UserRepository, otpRepository *repository.OTPRepository, adminRepository *repository.AdminRepository, configRepository *repository.ConfigRepository) *AuthenticateService {
	return &AuthenticateService{
		notification:     notification,
		userRepository:   userRepository,
		otpRepository:    otpRepository,
		adminRepository:  adminRepository,
		configRepository: configRepository,
	}
}

func (useServ *AuthenticateService) InsertCustomerService(input entity.Signupuser) (response entity.CustomResponse) {
	tx, errt := useServ.userRepository.Begin()
	if errt != nil {
		response.Resultcode = 1
		response.Message = errt.Error()
		return response
	}
	resp, err := useServ.userRepository.InsertNewCustomer(tx, input)
	if err != nil {
		tx.Rollback()
		response.Resultcode = 1
		response.Message = resp + err.Error()
	} else {
		commitError := tx.Commit()
		if commitError != nil {
			response.Resultcode = 1
			response.Message = resp + err.Error()

		} else {
			response.Resultcode = 0
			response.Message = resp

		}
	}
	return response
}

func (useServ *AuthenticateService) VerifyOTPCustomerService(mobno string, otp int64) (response entity.CustomResponse) {
	otpResponse, err := useServ.otpRepository.VerifyOTP(mobno, 0, otp)
	if err == nil {
		if otpResponse {
			response.Resultcode = 0
			response.Message = dto.SuccessMessageVerifyOTP
		} else {
			response.Resultcode = 1
			response.Message = dto.ErrorMessageforVerifyOTP
		}
	} else {
		response.Resultcode = 1
		response.Message = dto.ErrorMessageforVerifyOTPExpiry
	}
	if response.Resultcode == 0 {
		token := util.JWTAuthService().GenerateToken(mobno, false)
		response.Token = &token
	}
	return response
}

func (useServ *AuthenticateService) AuthenticateCustomerService(mobileno string) (response entity.CustomResponse) {
	userResponse, merr := useServ.userRepository.FetchUserbyMobno(mobileno)
	if merr == nil || merr == sql.ErrNoRows {
		otp, err := useServ.notification.SendOTP(mobileno)
		if err != nil {
			response.Message = dto.ErrorMessageforAuthenticateCustomer + err.Error()
			response.Resultcode = 1
		} else {
			var userType string
			if merr == sql.ErrNoRows {
				userResponse = &entity.User{}
				userType = "New Signup"
				userResponse.User_Login_type = &userType
			} else {
				userType = "Existing Signup"
				userResponse.User_Login_type = &userType
			}

			if userResponse.Mapped_Apartments != nil {
				//log.Println(fmt.Sprint("(", *userResponse.Mapped_Apartments, ")"))
				//log.Println(useServ.configRepository)
				if *userResponse.Apartment_Id != "" {
					*userResponse.Mapped_Apartments = fmt.Sprint("(", *userResponse.Apartment_Id, ",", *userResponse.Mapped_Apartments, ")")
				} else {
					*userResponse.Mapped_Apartments = fmt.Sprint("(", *userResponse.Mapped_Apartments, ")")
				}

				userResponse.Mapped_Apartment_list, _ = useServ.configRepository.FetchApartmentsById(*userResponse.Mapped_Apartments, 1,mobileno )

			} else {
				if userResponse.Apartment_Id != nil {
					apartments := fmt.Sprint("(", *userResponse.Apartment_Id, ")")
					userResponse.Mapped_Apartments = &apartments
					userResponse.Mapped_Apartment_list, _ = useServ.configRepository.FetchApartmentsById(*userResponse.Mapped_Apartments, 1,mobileno)
				}
			}
			userResponse.OTP = &otp
			useServ.otpRepository.StoreOTP(mobileno, otp)
			response.Message = dto.SuccessMessageAuthenticateCustomer
			response.Resultcode = 0
			response.Payload = userResponse
		}
	} else {
		response.Message = dto.ErrorMessageforAuthenticateCustomer + merr.Error()
		response.Resultcode = 1
	}
	if response.Resultcode == 0 {
		token := util.JWTAuthService().GenerateToken(mobileno, false)
		response.Token = &token
	}
	return response
}

func (authServ *AuthenticateService) AuthenticateAdminService(mobileno string, languagecode int) (response entity.CustomResponse) {
	userResponse, err := authServ.adminRepository.FetchAdminbyMobno(mobileno, languagecode)
	if err != nil {
		if err == sql.ErrNoRows {
			response.Resultcode = 1
			response.Message = "No Admin found. Please signup"
		} else {
			response.Message = dto.ErrorMessageforAuthenticateCustomer + err.Error()
			response.Resultcode = 1
		}
	} else {
		otp, err := authServ.notification.SendOTP(mobileno)
		userResponse.OTP = otp
		if err != nil {
			response.Message = dto.ErrorMessageforAuthenticateCustomer + err.Error()
			response.Resultcode = 1
		} else {
			authServ.otpRepository.StoreOTP(mobileno, otp)
			response.Message = dto.SuccessMessageAuthenticateCustomer
			response.Resultcode = 0
			response.Payload = userResponse
		}
	}
	//log.Print(util.JWTAuthService())
	token := util.JWTAuthService().GenerateToken(mobileno, false)
	response.Token = &token
	return response
}
