package handler

import (
	"errors"
	"fmt"
	"time"

	"git.coopgo.io/coopgo-platform/carpool-service/internal"
	"git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
	"github.com/google/uuid"
	"github.com/rs/zerolog/log"
)

// Book handles the booking flow
func (h *CarpoolServiceHandler) Book(booking ocss.Booking) (*internal.Booking, error) {
	log.Debug().Any("booking", booking).Msg("handler - Book")
	log.Debug().Str("passengerPickupDate", booking.PassengerPickupDate.ToTime().Format(time.RFC3339)).Msg("handler - Book")
	futureBooking := internal.Booking{}
	roles := []string{}
	if booking.Driver.Operator == h.InternalOperatorID {
		roles = append(roles, "driver")
		previous_search_result, err := h.Storage.GetRouteSchedule(booking.DriverJourneyID)
		if err == nil {
			futureBooking.DriverRoute = previous_search_result.Route
		}
	}

	if booking.Passenger.Operator == h.InternalOperatorID {
		roles = append(roles, "passenger")
		previous_search_result, err := h.Storage.GetRouteSchedule(booking.PassengerJourneyID)
		if err != nil {
			log.Error().Err(err).Msg("could not get previous result")
		}
		if err == nil {
			futureBooking.PassengerRoute = previous_search_result.Route
		}
	}

	if len(roles) == 0 {
		return nil, fmt.Errorf("couldn't find the right operator id : \"%s\" should be set for driver or passenger", h.InternalOperatorID)
	}

	if _, err := uuid.Parse(booking.ID); err != nil {
		return nil, errors.New("bookingid is not a valid uuid")
	}

	futureBooking.Booking = booking

	err := h.Storage.CreateBooking(futureBooking)
	if err != nil {
		log.Error().Err(err).Msg("issue creating booking in database")
		return nil, err
	}

	return &futureBooking, nil
}

// GetBooking returns the booking with the given ID
func (h *CarpoolServiceHandler) GetBooking(id string) (*internal.Booking, error) {
	booking, err := h.Storage.GetBooking(id)
	if err != nil {
		log.Error().Err(err).Msg("issue retrieving booking in storage")
		return nil, errors.New("booking id not found")
	}
	return booking, nil
}

// GetUserBookings retrieves all the bookings for a specified user id
func (h *CarpoolServiceHandler) GetUserBookings(user_id string, mindate *time.Time, maxdate *time.Time) ([]internal.Booking, error) {
	bookings, err := h.Storage.GetUserBookings(user_id)
	if err != nil {
		return nil, err
	}

	results := []internal.Booking{}

	for _, b := range bookings {
		if mindate != nil {
			if b.PassengerPickupDate.ToTime().Before(*mindate) {
				continue
			}
		}
		if maxdate != nil {
			if b.PassengerPickupDate.ToTime().After(*maxdate) {
				continue
			}
		}
		results = append(results, b)
	}

	return results, nil
}

// UpdateBookingStatus sets a new status for a given booking id
func (h *CarpoolServiceHandler) UpdateBookingStatus(id string, status ocss.BookingStatus) error {
	err := h.Storage.UpdateBookingStatus(id, status.String())
	if err != nil {
		log.Error().Err(err).Msg("not able to update booking status")
		return err
	}
	return nil
}