package services

import (
	dto "astrology-api/dto"
	models "astrology-api/models/usermodel"
	repositories "astrology-api/repositories"

	"gorm.io/gorm"
)

type OrderAddressService interface {

	// Add Address
	AddOrderAddress(userID uint, req *dto.AddOrderAddressRequest) (*models.OrderAddress, error)

	// Update Address
	UpdateOrderAddress(id uint, userID uint, req *dto.UpdateOrderAddressRequest) (*models.OrderAddress, error)

	// Address List
	GetOrderAddresses(userID uint, search string) ([]dto.OrderAddressResponse, error)
}

type orderAddressService struct {
	db         *gorm.DB
	repository repositories.OrderAddressRepository
}

func NewOrderAddressService(
	db *gorm.DB,
	repository repositories.OrderAddressRepository,
) OrderAddressService {

	return &orderAddressService{
		db:         db,
		repository: repository,
	}
}

//
// Add Order Address
//
func (s *orderAddressService) AddOrderAddress(
	userID uint,
	req *dto.AddOrderAddressRequest,
) (*models.OrderAddress, error) {

	tx := s.db.Begin()

	address := &models.OrderAddress{
		UserID:               userID,
		Name:                 req.Name,
		PhoneNumber:          req.PhoneNumber,
		PhoneNumber2:         req.PhoneNumber2,
		FlatNo:               req.FlatNo,
		Locality:             req.Locality,
		Landmark:             req.Landmark,
		City:                 req.City,
		State:                req.State,
		Country:              req.Country,
		Pincode:              req.Pincode,
		CountryCode:          req.CountryCode,
		AlternateCountryCode: req.AlternateCountryCode,
		IsActive:             true,
		IsDelete:             false,
		CreatedBy:            int(userID),
		ModifiedBy:           int(userID),
	}

	if err := s.repository.AddOrderAddress(tx, address); err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()

	return address, nil
}

//
// Update Order Address
//
func (s *orderAddressService) UpdateOrderAddress(
	id uint,
	userID uint,
	req *dto.UpdateOrderAddressRequest,
) (*models.OrderAddress, error) {

	tx := s.db.Begin()

	address, err := s.repository.GetOrderAddressByID(id)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	// Security Check
	if address.UserID != userID {
		tx.Rollback()
		return nil, gorm.ErrRecordNotFound
	}

	address.Name = req.Name
	address.PhoneNumber = req.PhoneNumber
	address.PhoneNumber2 = req.PhoneNumber2
	address.FlatNo = req.FlatNo
	address.Locality = req.Locality
	address.Landmark = req.Landmark
	address.City = req.City
	address.State = req.State
	address.Country = req.Country
	address.Pincode = req.Pincode
	address.CountryCode = req.CountryCode
	address.AlternateCountryCode = req.AlternateCountryCode
	address.ModifiedBy = int(userID)

	if err := s.repository.UpdateOrderAddress(tx, address); err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()

	return address, nil
}

//
// Get Order Address List
//
func (s *orderAddressService) GetOrderAddresses(
	userID uint,
	search string,
) ([]dto.OrderAddressResponse, error) {

	addresses, err := s.repository.GetOrderAddresses(userID, search)
	if err != nil {
		return nil, err
	}

	response := make([]dto.OrderAddressResponse, 0)

	for _, address := range addresses {

		response = append(response, dto.OrderAddressResponse{
			ID:                   address.ID,
			UserID:               address.UserID,
			Name:                 address.Name,
			PhoneNumber:          address.PhoneNumber,
			PhoneNumber2:         address.PhoneNumber2,
			FlatNo:               address.FlatNo,
			Locality:             address.Locality,
			Landmark:             address.Landmark,
			City:                 address.City,
			State:                address.State,
			Country:              address.Country,
			Pincode:              address.Pincode,
			CountryCode:          address.CountryCode,
			AlternateCountryCode: address.AlternateCountryCode,
		})
	}

	return response, nil
}