package services

import (
	"net/url"

	dto "astrology-api/dto/astrology"
)

//////////////////////////////////////////////////////////////
// Numerology Service
//////////////////////////////////////////////////////////////

type NumerologyService interface {
	Report(userID uint, req dto.NumerologyRequest) (*dto.VedicDataResponse, error)
	DayNumber(userID uint, req dto.DayNumberRequest) (*dto.VedicDataResponse, error)
	Table(userID uint, req dto.NumeroTableRequest) (*dto.VedicDataResponse, error)
	RadicalNumber(req dto.RadicalNumberRequest) (*dto.VedicDataResponse, error)
}

type numerologyService struct {
	astrologyBase
}

func NewNumerologyService() NumerologyService {
	return &numerologyService{astrologyBase: newAstrologyBase()}
}

func (s *numerologyService) fetch(
	userID uint,
	path string,
	params url.Values,
) (*dto.VedicDataResponse, error) {

	client, err := s.vedic()

	if err != nil {
		return nil, err
	}

	data, err := client.Get(path, params)

	if err != nil {
		return nil, err
	}

	charged, err := s.chargeForRead(userID, FlagPriceNumerology, TxnNumerology)

	if err != nil {
		return nil, err
	}

	return &dto.VedicDataResponse{Charged: charged, Data: data}, nil
}

//////////////////////////////////////////////////////////////
// Report
//////////////////////////////////////////////////////////////

func (s *numerologyService) Report(
	userID uint,
	req dto.NumerologyRequest,
) (*dto.VedicDataResponse, error) {

	date, err := ToVedicDate(req.BirthDate)

	if err != nil {
		return nil, err
	}

	params := url.Values{}
	params.Set("name", req.Name)
	params.Set("date", date)
	params.Set("lang", req.Lang)

	return s.fetch(userID, "prediction/numerology", params)
}

//////////////////////////////////////////////////////////////
// Day Number
//////////////////////////////////////////////////////////////

func (s *numerologyService) DayNumber(
	userID uint,
	req dto.DayNumberRequest,
) (*dto.VedicDataResponse, error) {

	dob, err := ToVedicDate(req.BirthDate)

	if err != nil {
		return nil, err
	}

	params := url.Values{}
	params.Set("dob", dob)
	params.Set("lang", req.Lang)

	return s.fetch(userID, "prediction/day-number", params)
}

//////////////////////////////////////////////////////////////
// Numero Table
//////////////////////////////////////////////////////////////

func (s *numerologyService) Table(
	userID uint,
	req dto.NumeroTableRequest,
) (*dto.VedicDataResponse, error) {

	dob, err := ToVedicDate(req.BirthDate)

	if err != nil {
		return nil, err
	}

	params := url.Values{}
	params.Set("name", req.Name)
	params.Set("dob", dob)
	params.Set("tob", req.BirthTime)
	params.Set("lat", FormatFloat(req.Latitude))
	params.Set("lon", FormatFloat(req.Longitude))
	params.Set("tz", FormatFloat(DefaultTimezone(req.Timezone)))
	params.Set("lang", req.Lang)

	return s.fetch(userID, "extended-horoscope/numero-table", params)
}

//////////////////////////////////////////////////////////////
// Radical Number
//////////////////////////////////////////////////////////////

// RadicalNumber is static reference content, so it is never charged.
func (s *numerologyService) RadicalNumber(
	req dto.RadicalNumberRequest,
) (*dto.VedicDataResponse, error) {

	client, err := s.vedic()

	if err != nil {
		return nil, err
	}

	params := url.Values{}
	params.Set("radical_number", itoa(req.RadicalNumber))
	params.Set("lang", req.Lang)

	data, err := client.Get("utilities/radical-number-details", params)

	if err != nil {
		return nil, err
	}

	return &dto.VedicDataResponse{Data: data}, nil
}

// NewNumerologyServiceForAstrologer is the same service for the astrologer routes,
// which never charge.
func NewNumerologyServiceForAstrologer() NumerologyService {
	return &numerologyService{astrologyBase: freeAstrologyBase()}
}
