package storage

import (
	"github.com/paulmach/orb"
	"github.com/paulmach/orb/geojson"
	"go.mongodb.org/mongo-driver/mongo" 
	"github.com/spf13/viper"
	"go.mongodb.org/mongo-driver/mongo/options"
	"solidarity-service/utils"
	"context"
	"github.com/google/uuid"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/lib/pq"
	"github.com/rs/zerolog/log"
	"strings"
	"sync"
	"time"
	"go.mongodb.org/mongo-driver/bson"
	"solidarity-service/internal"

)

type MongoDBStorage struct {
	*mongo.Client
	DbName      string
	Collections map[string]string
}

func NewMongoDBStorage(cfg *viper.Viper) (MongoDBStorage, error) {
	var (
		mongodb_host   = cfg.GetString("storage.db.mongodb.host")
		mongodb_port   = cfg.GetString("storage.db.mongodb.port")
		mongodb_dbname = cfg.GetString("storage.db.mongodb.db_name")
		mongodb_groups = cfg.GetString("storage.db.mongodb.collections.groups")
		////////////////////////code
		mongodb_groups_members = cfg.GetString("storage.db.mongodb.collections.groups_member")
	)

	client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://" + mongodb_host + ":" + mongodb_port))
	if err != nil {
		return MongoDBStorage{}, err
	}

	err = client.Connect(context.TODO())

	if err != nil {
		return MongoDBStorage{}, err
	}

	storage := MongoDBStorage{
		Client: client,
		DbName: mongodb_dbname,
		Collections: map[string]string{
			"groups": mongodb_groups,
			/////////////////////////////code
			"groups_member": mongodb_groups_members,
		},
	}
	//TODO Indexes
	return storage, err
}

func (s MongoDBStorage) CreatePassenger(passenger internal.Passenger) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["passengers"])

	_, err = uuid.Parse(passenger.Passenger.ID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage CreatePassenger invalid ID")
		return err
	}

	if passenger.Passenger.Alias == "" || passenger.Passenger.Operator == "" {
		errMsg := "MongoDB Storage CreatePassenger empty alias or operator FQDN."
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	// preferencesJSON, err := json.Marshal(passenger.Preferences)
	if err != nil {
		errMsg := "MongoDB Storage CreatePassenger Error encoding Preferences to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	if _, err := collection.InsertOne(context.TODO(), passenger); err != nil {
		return err
	}

	// if err != nil {
	// 	if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
	// 		err = s.UpdatePassenger(passenger)
	// 		if err != nil {
	// 			return err
	// 		}
	// 		return nil
	// 	}
	// 	errMsg := "Postgresql Storage CreatePassenger Error inserting data into the database"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return errors.New(errMsg + err.Error())
	// }
	return nil
}
func (s MongoDBStorage) UpdatePassenger(passenger internal.Passenger) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["passengers"])

	_, err = uuid.Parse(passenger.Passenger.ID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage UpdatePassenger invalid ID")
		return err
	}
	if passenger.Passenger.Alias == "" || passenger.Passenger.Operator == "" {
		errMsg := "MongoDB Storage UpdatePassenger empty alias or operator FQDN."
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	// preferencesJSON, err := json.Marshal(passenger.Preferences)
	if err != nil {
		errMsg := "MongoDB Storage UpdatePassenger Error encoding Preferences to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	if _, err := collection.ReplaceOne(context.TODO(), bson.M{"_id": passenger.Passenger.ID}, passenger); err != nil {
		fmt.Println(err)
		return err
	}
	if err != nil {
		errMsg := "MongoDB Storage UpdatePassenger Error updating data in the database"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	return nil
}

func (s MongoDBStorage) GetPassenger(passengerID string) (passenger internal.Passenger, err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["passengers"])

	var preferencesJSON []byte
	_ , err = uuid.Parse(passenger.Passenger.ID)
	if len(passengerID) == 0 {
		return passenger, errors.New("no group id provided")
	} else {
		_, err = collection.Find(context.TODO(), bson.M{"_id": bson.M{"$in": passengerID}})
		if err != nil {
			return passenger, err
		}
	}

	if err != nil {
		errMsg := "MongoDB Storage GetPassenger Error querying data from the database"
		log.Error().Err(err).Msg(errMsg)
		return passenger, errors.New(errMsg + err.Error())
	}

	err = json.Unmarshal(preferencesJSON, &passenger.Preferences)
	if err != nil {
		errMsg := "MongoDB Storage GetPassenger Error decoding Preferences from JSON"
		log.Error().Err(err).Msg(errMsg)
		return passenger, errors.New(errMsg + err.Error())
	}
	return passenger, nil
}

func (s MongoDBStorage) CreateDriver(driver internal.Driver) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["drivers"])
	//var availabilities []byte
	_, err = uuid.Parse(driver.Driver.ID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage CreateDriver invalid ID")
		return err
	}
	//departureJSON, err := json.Marshal(driver.Driver_departure_address)
	if err != nil {
		errMsg := "MongoDB Storage CreateDriver Error encoding departure Feature to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	//preferencesJSON, err := json.Marshal(driver.Preferences)
	if err != nil {
		errMsg := "MongoDB Storage CreateDriver Error encoding Preferences to JSON"
		log.Error().Err(err).Msg(errMsg + err.Error())
		return errors.New(errMsg)
	}
	//carJSON, err := json.Marshal(driver.Car)
	if err != nil {
		errMsg := "MongoDB Storage CreateDriver Error encoding Car to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	if driver.Driver.Alias == "" || driver.Driver.Operator == "" {
		errMsg := "MongoDB Storage CreateDriver empty alias or operator FQDN."
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	if driver.AvailabilitiesType != internal.Punctual && driver.AvailabilitiesType != internal.Regular {
		errMsg := "MongoDB Storage CreateDriver invalid Availabilities Type"
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	if driver.Radius == 0 {
		errMsg := "MongoDB Storage CreateDriver Radius has to be defined"
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	switch driver.AvailabilitiesType {
	case internal.Punctual:
		//availabilities, err = json.Marshal(driver.PunctualAvailabilities)
		if err != nil {
			errMsg := "MongoDB Storage CreateDriver error converting Punctual availabilities"
			log.Error().Msg(errMsg)
			return errors.New(errMsg + err.Error())
		}
	case internal.Regular:
		//availabilities, err = json.Marshal(driver.RegularAvailabilities)
		if err != nil {
			errMsg := "MongoDB Storage CreateDriver error converting Regular availabilities"
			log.Error().Msg(errMsg)
			return errors.New(errMsg + err.Error())
		}
	}
	if _, err := collection.InsertOne(context.TODO(), driver); err != nil {
		return err
	}
	// if err != nil {
	// 	if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
	// 		err = s.UpdateDriver(driver)
	// 		if err != nil {
	// 			return err
	// 		}
	// 		return nil
	// 	}
	// 	errMsg := "MongoDB Storage CreateDriver Error inserting data into the database"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return errors.New(errMsg + err.Error())
	// }
	return nil
}
func (s MongoDBStorage) UpdateDriver(driver internal.Driver) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["drivers"])
	//var availabilities []byte
	_, err = uuid.Parse(driver.Driver.ID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage UpdateDriver invalid ID")
		return err
	}
	//departureJSON, err := json.Marshal(driver.Driver_departure_address)
	if err != nil {
		errMsg := "MongoDB Storage UpdateDriver Error encoding departure Feature to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	//preferencesJSON, err := json.Marshal(driver.Preferences)
	if err != nil {
		errMsg := "MongoDB Storage UpdateDriver Error encoding Preferences to JSON"
		log.Error().Err(err).Msg(errMsg + err.Error())
		return errors.New(errMsg)
	}
	//carJSON, err := json.Marshal(driver.Car)
	if err != nil {
		errMsg := "MongoDB Storage UpdateDriver Error encoding Car to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	if driver.Driver.Alias == "" || driver.Driver.Operator == "" {
		errMsg := "MongoDB Storage UpdateDriver empty alias or operator FQDN."
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	if driver.AvailabilitiesType != internal.Punctual && driver.AvailabilitiesType != internal.Regular {
		errMsg := "MongoDB Storage UpdateDriver invalid Availabilities Type"
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	if driver.Radius == 0 {
		errMsg := "MongoDB Storage UpdateDriver Radius has to be defined"
		log.Error().Msg(errMsg)
		return errors.New(errMsg)
	}
	// switch driver.AvailabilitiesType {
	// case internal.Punctual:
	// 	availabilities, err = json.Marshal(driver.PunctualAvailabilities)
	// 	if err != nil {
	// 		errMsg := "MongoDB Storage UpdateDriver error converting Punctual availabilities"
	// 		log.Error().Msg(errMsg)
	// 		return errors.New(errMsg + err.Error())
	// 	}
	// case internal.Regular:
	// 	availabilities, err = json.Marshal(driver.RegularAvailabilities)
	// 	if err != nil {
	// 		errMsg := "MongoDB Storage UpdateDriver error converting Regular availabilities"
	// 		log.Error().Msg(errMsg)
	// 		return errors.New(errMsg + err.Error())
	// 	}
	// }

	if _, err := collection.ReplaceOne(context.TODO(), bson.M{"_id": driver.Driver.ID}, driver); err != nil {
		fmt.Println(err)
		return err
	}
	if err != nil {
		errMsg := "MongoDB Storage UpdateDriver Error updating data in the database"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	return nil
}

func (s MongoDBStorage) GetDriver(driverID string) ( *internal.Driver, error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["drivers"])
	// var preferencesJSON []byte
	// var departureAddress []byte
	// var availabilitiesJSON []byte
	// var carJSON []byte
	driver := &internal.Driver{}
	if err := collection.FindOne(context.TODO(), bson.M{"_id": driverID}).Decode(driver); err != nil {
		return nil, err
	}
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetDriver Error querying data from the database"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return driver, errors.New(errMsg + err.Error())
	// }

	// err = json.Unmarshal(preferencesJSON, &driver.Preferences)
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetDriver Error decoding Preferences from JSON"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return driver, errors.New(errMsg + err.Error())
	// }
	// err = json.Unmarshal(carJSON, &driver.Car)
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetDriver Error decoding Car from JSON"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return driver, errors.New(errMsg + err.Error())
	// }
	// driver.Driver_departure_address, err = geojson.UnmarshalFeature(departureAddress)
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetDriver Error decoding Driver departure route into GeoJSON"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return driver, errors.New(errMsg + err.Error())
	// }

	// switch driver.AvailabilitiesType {
	// case Regular:
	// 	err = json.Unmarshal(availabilitiesJSON, &driver.RegularAvailabilities)
	// 	if err != nil {
	// 		errMsg := "MongoDB Storage GetDriver Error decoding Regular Availabilities from JSON"
	// 		log.Error().Err(err).Msg(errMsg)
	// 		return driver, errors.New(errMsg + err.Error())
	// 	}
	// case Punctual:
	// 	err = json.Unmarshal(availabilitiesJSON, &driver.PunctualAvailabilities)
	// 	if err != nil {
	// 		errMsg := "MongoDB Storage GetDriver Error decoding Punctual Availabilities from JSON"
	// 		log.Error().Err(err).Msg(errMsg)
	// 		return driver, errors.New(errMsg + err.Error())
	// 	}
	// default:
	// 	errMsg := "MongoDB Storage GetDriver Invalid Availabilities Type"
	// 	log.Error().Msg(errMsg)
	// 	return driver, errors.New(errMsg + err.Error())
	// }

	return driver, nil
}

func (s MongoDBStorage) CreateBooking(booking internal.BookingRequest) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
	_, err = uuid.Parse(booking.Driver_id)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage CreateBooking invalid Driver ID")
		return err
	}
	_, err = uuid.Parse(booking.Passenger_id)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage CreateBooking invalid Passenger ID")
		return err
	}
	_, err = uuid.Parse(booking.ID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage CreateBooking invalid Booking ID")
		return err
	}
	if booking.Operator == "" {
		log.Error().Err(err).Msg("MongoDB Storage CreateBooking empty operator")
		return err
	}
	//departureJSON, err := json.Marshal(booking.Departure_address)
	if err != nil {
		errMsg := "MongoDB Storage CreateBooking Error encoding departure Feature to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}

	//destinationJSON, err := json.Marshal(booking.Destination_address)
	if err != nil {
		errMsg := "MongoDB Storage CreateBooking Error converting destination Feature to JSON"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	if booking.Pickup_date == 0 {
		errMsg := "MongoDB Storage CreateBooking empty UNIX pickup Date timestamp"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg)
	}
	booking.Distance = utils.Haversine(booking.Departure_address.Point().Lat(), booking.Departure_address.Point().Lon(),
		booking.Destination_address.Point().Lat(), booking.Destination_address.Point().Lon())
	booking.Duration, _ = utils.CalculateDurationBetweenFeatures(booking.Departure_address, booking.Destination_address)
	if _, err := collection.InsertOne(context.TODO(), booking); err != nil {
		return err
	}
	if err != nil {
		errMsg := "MongoDB Storage CreateBooking Error inserting data into the database"
		log.Error().Err(err).Msg(errMsg)
		return errors.New(errMsg + err.Error())
	}
	return nil
}

func (s MongoDBStorage) GetBooking(bookingID string) (*internal.Booking, error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
	//var departureAddress []byte
	//var destinationAddress []byte
	booking := &internal.Booking{}
	if err := collection.FindOne(context.TODO(), bson.M{"_id": bookingID}).Decode(booking); err != nil {
		return nil, err
	}

	// if err != nil {
	// 	errMsg := "MongoDB Storage GetBooking Error getting booking"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return internal.Booking{}, errors.New(errMsg + err.Error())
	// }
	// booking.PassengerPickupAddress, err = geojson.UnmarshalFeature(departureAddress)
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetBooking Error decoding Driver departure route into GeoJSON"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return internal.Booking{}, errors.New(errMsg + err.Error())
	// }
	// booking.PassengerDropAddress, err = geojson.UnmarshalFeature(destinationAddress)
	// if err != nil {
	// 	errMsg := "MongoDB Storage GetBooking Error decoding Driver destination route into GeoJSON"
	// 	log.Error().Err(err).Msg(errMsg)
	// 	return internal.Booking{}, errors.New(errMsg + err.Error())
	// }
	passenger, err := s.GetPassenger(booking.Passenger.ID)
	if err != nil {
		errMsg := "MongoDB Storage GetBooking Error getting passenger"
		log.Error().Err(err).Msg(errMsg)
		return booking, errors.New(errMsg + err.Error())
	}
	booking.Passenger = passenger.Passenger
	driver, err := s.GetDriver(booking.Driver.ID)
	if err != nil {
		errMsg := "MongoDB Storage GetBooking Error getting driver"
		log.Error().Err(err).Msg(errMsg)
		return booking, errors.New(errMsg + err.Error())
	}
	booking.Driver = driver.Driver
	return booking, nil
}

func (s MongoDBStorage) UpdateBookingStatus(bookingStatusID string, status internal.BookingStatus) (err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
	_, err = uuid.Parse(bookingStatusID)
	if err != nil {
		log.Error().Err(err).Msg("MongoDB Storage UpdateBookingStatus invalid Booking ID")
		return err
	}
	_, err = s.GetBooking(bookingStatusID)
	if err != nil {
		return errors.New(err.Error())
	}
	if _, err := collection.ReplaceOne(context.TODO(), bson.M{"_id": bookingStatusID}, status); err != nil {
		fmt.Println(err)
		return err
	}


	return nil
}

func (s MongoDBStorage) FilterUserBookingsByStatus(userType string, status internal.BookingStatus, userID string) (bookings []internal.Booking, err error) {
	collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
	if err != nil {
		return nil, errors.New("invalid UUID")
	}

	if userType != "driver" && userType != "passenger" {
		return nil, errors.New("invalid user type")
	}

	var cur *mongo.Cursor   

	findOptions := options.Find()

	if len(userID) == 0 {
		return bookings, errors.New("no group id provided")
	} else {
		cur, err = collection.Find(context.TODO(), bson.M{"_id": bson.M{"$in": userID}}, findOptions)
		if err != nil {
			return bookings, err
		}
	}

	for cur.Next(context.TODO()) {
		var group internal.Booking
		var elem bson.M

		if err := cur.Decode(&elem); err != nil {
			return bookings, err
		}

		bsonBytes, _ := bson.Marshal(elem)
		bson.Unmarshal(bsonBytes, &group)

		bookings = append(bookings, group)

	}
	var wg sync.WaitGroup
	//var mu sync.Mutex

	// for rows.Next() {
	// 	var departureAddress []byte
	// 	var destinationAddress []byte
	// 	var booking internal.Booking

	// 	if err := rows.Scan(&booking.ID, &booking.Passenger.ID, &booking.Driver.ID, &booking.Status, &departureAddress, &destinationAddress, &booking.Pickup_date, &booking.Duration, &booking.Distance); err != nil {
	// 		return nil, err
	// 	}

	// 	wg.Add(1)
	// 	go func(booking internal.Booking, departureAddress, destinationAddress []byte) {
	// 		defer wg.Done()

	// 		// Common logic for both "driver" and "passenger" cases
	// 		booking, err := s.populateBookingDetails(booking, departureAddress, destinationAddress)
	// 		if err != nil {
	// 			mu.Lock()
	// 			err = fmt.Errorf("Error populating booking details: %w", err)
	// 			mu.Unlock()
	// 			return
	// 		}

	// 		mu.Lock()
	// 		bookings = append(bookings, booking)
	// 		mu.Unlock()
	// 	}(booking, departureAddress, destinationAddress)
	// }

	// Wait for all goroutines to finish
	wg.Wait()

	// if err := rows.Err(); err != nil {
	// 	return nil, err
	// }

	return bookings, nil
}

func (s MongoDBStorage) populateBookingDetails(booking internal.Booking, departureAddress, destinationAddress []byte) (internal.Booking, error) {
	var wg sync.WaitGroup
	var mu sync.Mutex
	errCh := make(chan error, 4) // Buffered channel to handle potential errors

	// Concurrently fetch passenger information
	wg.Add(1)
	go func() {
		defer wg.Done()

		passenger, err := s.GetPassenger(booking.Passenger.ID)
		if err != nil {
			errCh <- fmt.Errorf("MongoDB Storage GetBooking Error getting passenger: %w", err)
			return
		}

		mu.Lock()
		booking.Passenger = passenger.Passenger
		mu.Unlock()
	}()

	// Concurrently fetch driver information
	wg.Add(1)
	go func() {
		defer wg.Done()

		driver, err := s.GetDriver(booking.Driver.ID)
		if err != nil {
			errCh <- fmt.Errorf("MongoDB Storage GetBooking Error getting driver: %w", err)
			return
		}

		mu.Lock()
		booking.Driver = driver.Driver
		mu.Unlock()
	}()

	// Concurrently decode departureAddress into GeoJSON
	wg.Add(1)
	go func() {
		defer wg.Done()

		decodedDepartureAddress, err := geojson.UnmarshalFeature(departureAddress)
		if err != nil {
			errCh <- fmt.Errorf("MongoDB Storage FilterBookingsByStatus Error decoding Driver departure route into GeoJSON: %w", err)
			return
		}

		mu.Lock()
		booking.PassengerPickupAddress = decodedDepartureAddress
		mu.Unlock()
	}()

	// Concurrently decode destinationAddress into GeoJSON
	wg.Add(1)
	go func() {
		defer wg.Done()

		decodedDestinationAddress, err := geojson.UnmarshalFeature(destinationAddress)
		if err != nil {
			errCh <- fmt.Errorf("MongoDB Storage FilterBookingsByStatus Error decoding Driver destination route into GeoJSON: %w", err)
			return
		}

		mu.Lock()
		booking.PassengerDropAddress = decodedDestinationAddress
		mu.Unlock()
	}()

	// Close the error channel after all goroutines are done
	go func() {
		wg.Wait()
		close(errCh)
	}()

	// Check for errors using a select statement
	for err := range errCh {
		return internal.Booking{}, err // Return the first error encountered
	}

	return booking, nil
}

func (s MongoDBStorage) GetAllDrivers( date int64) (drivers []internal.Driver, err error) {
	// rows := s.Client.Database(s.DbName).Collection(s.Collections["drivers"])
	if err != nil {
		return nil, err
	}
	// defer rows.Close()

	//for rows.Next(ctx) {
		var driver internal.Driver
		var departureRoute []byte
		var preferencesJSON []byte
		var availabilitiesJSON []byte
		var carJSON []byte

		// if err := rows.Scan(
		// 	&driver.Driver.ID,
		// 	&departureRoute,
		// 	&driver.Radius,
		// 	&driver.Driver.LastName,
		// 	&driver.Driver.FirstName,
		// 	&driver.Driver.Grade,
		// 	&driver.Driver.Alias,
		// 	&driver.Driver.Picture,
		// 	&driver.Driver.VerifiedIdentity,
		// 	&preferencesJSON,
		// 	&driver.AvailabilitiesType,
		// 	&availabilitiesJSON,
		// 	&driver.Driver.Operator,
		// 	&carJSON,
		// ); err != nil {
		// 	return nil, err
		// }

		if err := json.Unmarshal(departureRoute, &driver.Driver_departure_address); err != nil {
			return nil, err
		}
		if err := json.Unmarshal(preferencesJSON, &driver.Preferences); err != nil {
			return nil, err
		}
		if err := json.Unmarshal(carJSON, &driver.Car); err != nil {
			return nil, err
		}

		// Filter drivers based on date and time matching punctual or regular availabilities.
		if driver.AvailabilitiesType == internal.Punctual {
			if err := json.Unmarshal(availabilitiesJSON, &driver.PunctualAvailabilities); err != nil {
				return nil, err
			}
			year, month, day := time.Unix(date, 0).Date()
			dateHour := time.Unix(date, 0).UTC().Local()
			dateHour_string := dateHour.Format("3:04 PM")
			for _, avail := range driver.PunctualAvailabilities {
				availyear, availmonth, availday := time.Unix(avail.Date, 0).Date()
				if availyear == year && availmonth == month && availday == day {
					startTime, err := time.Parse("3:04 PM", avail.StartTime)
					if err != nil {
						return nil, err
					}

					endTime, err := time.Parse("3:04 PM", avail.EndTime)
					if err != nil {
						return nil, err
					}

					// Convert DateHour_string to time.Time
					dateHourTime, err := time.Parse("3:04 PM", dateHour_string)
					if err != nil {
						return nil, err
					}
					if dateHourTime.After(startTime) || dateHourTime.Equal(startTime) {
						if dateHourTime.Before(endTime) || dateHourTime.Equal(endTime) {
							drivers = append(drivers, driver)
						}
					}

				}
				// Check if the date and time match the punctual driver's availability.

			}
		} else if driver.AvailabilitiesType == internal.Regular {
			if err := json.Unmarshal(availabilitiesJSON, &driver.RegularAvailabilities); err != nil {
				return nil, err
			}

			dayOfWeek := strings.ToLower(time.Unix(date, 0).Local().Format("Mon"))
			dateHour := time.Unix(date, 0).UTC().Local()
			dateHour_string := dateHour.Format("3:04 PM")

			for _, avail := range driver.RegularAvailabilities {

				// Check if the day and time match the regular driver's availability.
				if strings.ToLower(avail.DayOfWeek) == dayOfWeek {
					startTime, err := time.Parse("3:04 PM", avail.StartTime)
					if err != nil {
						return nil, err
					}

					endTime, err := time.Parse("3:04 PM", avail.EndTime)
					if err != nil {
						return nil, err
					}

					// Convert DateHour_string to time.Time
					dateHourTime, err := time.Parse("3:04 PM", dateHour_string)
					if err != nil {
						return nil, err
					}

					if dateHourTime.After(startTime) || dateHourTime.Equal(startTime) {
						if dateHourTime.Before(endTime) || dateHourTime.Equal(endTime) {
							drivers = append(drivers, driver)
						}
					}
				}
			}
		}
	//}

	// if err := rows.Err(); err != nil {
	// 	return nil, err
	// }

	return drivers, nil
}

func (s MongoDBStorage) DriverJourneys(departure_route *geojson.Feature, departure_date int64) (drivers []internal.Driver, err error) {
	allDrivers, err := s.GetAllDrivers(departure_date)
	if err != nil {
		return nil, err
	}
	for _, driver := range allDrivers {
		// Check if the departure route is the same as the driver's departure route.
		if departure_route.Point().Y() == driver.Driver_departure_address.Point().Y() && departure_route.Point().X() == driver.Driver_departure_address.Point().X() {
			drivers = append(drivers, driver)
		} else {
			// Calculate the distance between the departure point and the driver's departure route.
			coords1 := departure_route.Geometry.(orb.Point)
			coords2 := driver.Driver_departure_address.Geometry.(orb.Point)
			distance := utils.Haversine(coords1[1], coords1[0], coords2[1], coords2[0])
			if int64(distance) <= int64(driver.Radius) {
				drivers = append(drivers, driver)
			}
		}
	}

	return drivers, nil
}
