/*
 * Solidarity Mobility API
 *
 * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
 *
 * API version: 1.0.0
 * Generated by: OpenAPI Generator (https://openapi-generator.tech)
 */

package openapi

import (
	"context"
	"github.com/paulmach/orb"
	"github.com/paulmach/orb/geojson"
	"github.com/spf13/viper"
	"net/http"
	"solidarity-service/handler"
	"solidarity-service/internal"
	"solidarity-service/storage"
	"strings"
)

// SearchAPIService is a service that implements the logic for the SearchAPIServicer
// This service should implement the business logic for every endpoint for the SearchAPI API.
// Include any external packages or services that will be required by this service.
type SearchAPIService struct {
	config  *viper.Viper
	handler *handler.SolidarityServiceHandler
	storage storage.Storage
}

// NewSearchAPIService creates a default api service
func NewSearchAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) SearchAPIServicer {
	return &SearchAPIService{
		config:  config,
		handler: handler,
		storage: storage,
	}
}

// GetDriverJourneys - Search for matching punctual planned outward driver journeys.
func (s *SearchAPIService) GetDriverJourneys(ctx context.Context, departureLat float32, departureLng float32, departureDate int32, operator string) (ImplResponse, error) {
	drivers, err := s.storage.DriverJourneys(&geojson.Feature{
		Type:     "Feature",
		Geometry: orb.Geometry(orb.Point{float64(departureLat), float64(departureLng)}),
	}, int64(departureDate))
	if err != nil {
		if strings.Contains(err.Error(), " no rows in result set") {
			return Response(http.StatusBadRequest, "ID not found in the database"), nil
		} else {
			return Response(http.StatusInternalServerError, nil), nil
		}
	}
	response := []DriverJourney{}
	for _, v := range drivers {
		temp := DriverJourney{}
		if v.AvailabilitiesType == internal.Regular && v.RegularAvailabilities != nil {
			for _, v := range v.RegularAvailabilities {
				temp.RegularAvailabilitySlot = append(temp.RegularAvailabilitySlot, RegularAvailabilitySlot{
					DayOfWeek: v.DayOfWeek,
					StartTime: v.StartTime,
					EndTime:   v.EndTime,
				})
			}
		} else if v.AvailabilitiesType == internal.Punctual && v.PunctualAvailabilities != nil {
			for _, v := range v.PunctualAvailabilities {
				temp.PunctualAvailabilitySlot = append(temp.PunctualAvailabilitySlot, PunctualAvailabilitySlot{
					Date:      int32(v.Date),
					StartTime: v.StartTime,
					EndTime:   v.EndTime,
				})
			}
		}
		tamp := DriverJourney{
			User: User{
				Id:               v.Driver.ID,
				Operator:         v.Driver.Operator,
				Alias:            v.Driver.Alias,
				FirstName:        v.Driver.FirstName,
				LastName:         v.Driver.LastName,
				Grade:            int32(v.Driver.Grade),
				Picture:          v.Driver.Picture,
				Gender:           v.Driver.Gender,
				VerifiedIdentity: v.Driver.VerifiedIdentity,
			},
			Car: Car{
				Model: v.Car.Model,
				Brand: v.Car.Brand,
			},
			DriverDepartureDate: int64(departureDate),
			Price: Price{
				Type: "FREE",
			},
			DriverDepartureAddress: v.Driver_departure_address.Properties.MustString("name"),
		}
		temp.DriverDepartureAddress = tamp.DriverDepartureAddress
		temp.Car = tamp.Car
		temp.User = tamp.User
		temp.DriverDepartureDate = tamp.DriverDepartureDate
		temp.Price = tamp.Price
		response = append(response, temp)
	}
	return Response(200, response), nil
}