package grpcserver

import (
	"context"
	"errors"
	"fmt"
	"solidarity-service/internal"
	"solidarity-service/servers/grpc/proto"
	"solidarity-service/utils"
	"strings"
	"sync"

	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/paulmach/orb"
	"github.com/paulmach/orb/geojson"
	"github.com/rs/zerolog/log"
	"google.golang.org/protobuf/types/known/emptypb"
)

func (s *SolidarityServiceServerImpl) SetDriverRegularAvailabilities(ctx context.Context, req *proto.DriverRegularAvailabilities) (resp *proto.DriverAvailabilitiesResponse, err error) {
	if req.DriverRequest.Driver.Id == "" || req.DriverRequest.Driver.Alias == "" || req.DriverAvailabilities == nil || req.DriverRequest.DriverAddress == nil || req.DriverRequest.DriverRadius == 0 {
		return &proto.DriverAvailabilitiesResponse{
			Success: false,
		}, errors.New("missing required fields")
	}
	
	driver := internal.Driver{
		Driver_departure_address: &geojson.Feature{
			Type:     "Feature",
			Geometry: orb.Geometry(orb.Point{req.DriverRequest.DriverAddress.Lat, req.DriverRequest.DriverAddress.Long}),
			Properties: geojson.Properties{
				"name": req.DriverRequest.DriverAddress.Address,
			},
		},
		Radius: req.DriverRequest.DriverRadius,
		Driver: internal.User{
			ID:    req.DriverRequest.Driver.Id,
			Alias: req.DriverRequest.Driver.Alias,
		},
		AvailabilitiesType: internal.Regular,
	}

	if req.DriverRequest.Driver.FirstName != "" {
		driver.Driver.FirstName = req.DriverRequest.Driver.FirstName
	}
	if req.DriverRequest.Driver.LastName != "" {
		driver.Driver.LastName = req.DriverRequest.Driver.LastName
	}
	if req.DriverRequest.Driver.Grade != 0 {
		driver.Driver.Grade = req.DriverRequest.Driver.Grade
	}
	if req.DriverRequest.Driver.Picture != "" {
		driver.Driver.Picture = req.DriverRequest.Driver.Picture
	}
	if req.DriverRequest.Driver.Gender != "" {
		driver.Driver.Gender = req.DriverRequest.Driver.Gender
	}
	if req.DriverRequest.Driver.VerifiedIdentity != false {
		driver.Driver.VerifiedIdentity = req.DriverRequest.Driver.VerifiedIdentity
	}

	if req.DriverRequest.Car != nil {
		driver.Car = internal.Car{
			Model: req.DriverRequest.Car.Model,
			Brand: req.DriverRequest.Car.Brand,
		}
	}
	if req.DriverRequest.Preferences != nil {
		driver.Preferences = internal.Preferences{
			Smoking:      req.DriverRequest.Preferences.Smoking,
			Animals:      req.DriverRequest.Preferences.Animals,
			Music:        req.DriverRequest.Preferences.Music,
			Is_talker:    req.DriverRequest.Preferences.IsTalker,
			Luggage_size: req.DriverRequest.Preferences.LuggageSize,
		}
	}
	for _, v := range req.DriverAvailabilities {
		driver.RegularAvailabilities = append(driver.RegularAvailabilities, internal.RegularAvailabilities{
			DayOfWeek: v.DayOfWeek.String(),
			StartTime: v.StartTime,
			EndTime:   v.EndTime,
		})
	}

	err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
	if err != nil {
		return &proto.DriverAvailabilitiesResponse{
			Success: false,
		}, err
	}
	return &proto.DriverAvailabilitiesResponse{
		Success: true,
	}, nil
}

func (s *SolidarityServiceServerImpl) SetDriverPunctualAvailabilities(ctx context.Context, req *proto.DriverPunctualAvailabilities) (resp *proto.DriverAvailabilitiesResponse, err error) {
	if req.DriverRequest.Driver.Id == "" || req.DriverRequest.Driver.Alias == "" || req.DriverAvailabilities == nil || req.DriverRequest.DriverAddress == nil || req.DriverRequest.DriverRadius == 0 {
		return &proto.DriverAvailabilitiesResponse{
			Success: false,
		}, errors.New("missing required fields")
	}
	driver := internal.Driver{
		Driver_departure_address: &geojson.Feature{
			Type:     "Feature",
			Geometry: orb.Geometry(orb.Point{req.DriverRequest.DriverAddress.Lat, req.DriverRequest.DriverAddress.Long}),
			Properties: geojson.Properties{
				"name": req.DriverRequest.DriverAddress.Address,
			},
		},
		Radius: req.DriverRequest.DriverRadius,
		Driver: internal.User{
			ID:    req.DriverRequest.Driver.Id,
			Alias: req.DriverRequest.Driver.Alias,
		},
		AvailabilitiesType: internal.Punctual,
	}

	if req.DriverRequest.Driver.FirstName != "" {
		driver.Driver.FirstName = req.DriverRequest.Driver.FirstName
	}
	if req.DriverRequest.Driver.LastName != "" {
		driver.Driver.LastName = req.DriverRequest.Driver.LastName
	}
	if req.DriverRequest.Driver.Grade != 0 {
		driver.Driver.Grade = req.DriverRequest.Driver.Grade
	}
	if req.DriverRequest.Driver.Picture != "" {
		driver.Driver.Picture = req.DriverRequest.Driver.Picture
	}
	if req.DriverRequest.Driver.Gender != ""{
		driver.Driver.Gender = req.DriverRequest.Driver.Gender
	}
	if req.DriverRequest.Driver.VerifiedIdentity != false {
		driver.Driver.VerifiedIdentity = req.DriverRequest.Driver.VerifiedIdentity
	}

	if req.DriverRequest.Car != nil {
		driver.Car = internal.Car{
			Model: req.DriverRequest.Car.Model,
			Brand: req.DriverRequest.Car.Brand,
		}
	}
	if req.DriverRequest.Preferences != nil {
		driver.Preferences = internal.Preferences{
			Smoking:      req.DriverRequest.Preferences.Smoking,
			Animals:      req.DriverRequest.Preferences.Animals,
			Music:        req.DriverRequest.Preferences.Music,
			Is_talker:    req.DriverRequest.Preferences.IsTalker,
			Luggage_size: req.DriverRequest.Preferences.LuggageSize,
		}
	}
	for _, v := range req.DriverAvailabilities {
		driver.PunctualAvailabilities = append(driver.PunctualAvailabilities, internal.PunctualAvailabilities{
			Date:      v.Date.Seconds,
			StartTime: v.StartTime,
			EndTime:   v.EndTime,
		})
	}

	err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
	if err != nil {
		return &proto.DriverAvailabilitiesResponse{
			Success: false,
		}, err
	}
	return &proto.DriverAvailabilitiesResponse{
		Success: true,
	}, nil
}

func (s *SolidarityServiceServerImpl) GetAllPassengers( ctx context.Context, _ *emptypb.Empty) (resp *proto.GetAllPassengersResponse, err error) {
	passengers, err := s.Handler.GetAllPassengers(context.Background())
	resp = &proto.GetAllPassengersResponse{
		Passenger: []*proto.User{},
	}
	response := []*proto.User{}
	for _, v := range passengers {
		temp := &proto.User{
				Id:               v.Passenger.ID,
				Alias:            v.Passenger.Alias,
				FirstName:        v.Passenger.FirstName,
				LastName:         v.Passenger.LastName,
				Grade:            v.Passenger.Grade,
				Picture:          v.Passenger.Picture,
				Gender:           v.Passenger.Gender,
				VerifiedIdentity: v.Passenger.VerifiedIdentity,
			}
		response = append(response, temp)
	}
	resp.Passenger = response
	return resp, nil
}

func (s *SolidarityServiceServerImpl) GetPassenger(ctx context.Context, req *proto.GetPassengerRequest) (resp *proto.GetPassengerResponse, er error){
	if req.Passenger.Id == ""  {
		return nil, errors.New("missing required DriverId")
	}
	p, err := s.Handler.GetPassenger(context.Background(), req.Passenger.Id)

	resp = &proto.GetPassengerResponse{
		Passenger: &proto.User{
			Id:               p.Passenger.ID,
				Alias:            p.Passenger.Alias,
				FirstName:        p.Passenger.FirstName,
				LastName:         p.Passenger.LastName,
				Grade:            p.Passenger.Grade,
				Picture:          p.Passenger.Picture,
				Gender:           p.Passenger.Gender,
				VerifiedIdentity: p.Passenger.VerifiedIdentity,
		},
	}

	if err != nil {
		fmt.Println("err getpassenger : ", err) 
	}else{
	 return resp, nil
	}

	return
}

func (s *SolidarityServiceServerImpl) CreateBookingSolidarity(ctx context.Context, req *proto.CreateBookingSolidarityRequest) (resp *proto.CreateBookingSolidarityResponse, err error) {
	if req.Booking.DriverId == "" || req.Booking.DepartureAddress == nil || req.Booking.DestinationAddress == nil || req.Booking.PassengerId == ""  || req.Booking.Id == "" || req.Booking.Status.String() == "" ||req.Booking.PickupDate.Seconds == 0 {
		return nil, errors.New("missing required elements")
	}

	bookingRequest := internal.BookingRequest{
		ID:           req.Booking.Id,
		Passenger_id: req.Booking.PassengerId,
		Driver_id:    req.Booking.DriverId,
		Status:       internal.BookingStatus(req.Booking.Status.String()),
		Destination_address: &geojson.Feature{
			Type:     "Feature",
			Geometry: orb.Geometry(orb.Point{req.Booking.DestinationAddress.Lat, req.Booking.DestinationAddress.Long}),
			Properties: geojson.Properties{
				"name": req.Booking.DestinationAddress.Address,
			},
		},
		Departure_address: &geojson.Feature{
			Type:     "Feature",
			Geometry: orb.Geometry(orb.Point{req.Booking.DepartureAddress.Lat, req.Booking.DepartureAddress.Long}),
			Properties: geojson.Properties{
				"name": req.Booking.DepartureAddress.Address,
			},
		},
		Pickup_date: req.Booking.PickupDate.Seconds,
	}
	passenger, driver, err := s.Handler.CreateBooking(context.Background(), bookingRequest)
	if err != nil {
		if strings.Contains(err.Error(), utils.SQL_DUPLICATE) {
			err = errors.New("ID is already used")
		}
		return nil, err
	}
	duration, err := s.Handler.CalculateDurationBetweenFeatures(bookingRequest.Departure_address, bookingRequest.Destination_address)
	if err != nil {
		duration = 0
	}
	distance := s.Handler.CalculateDistanceBetweenFeatures(bookingRequest.Departure_address, bookingRequest.Destination_address)
	priceType := proto.PriceType_FREE
	resp = &proto.CreateBookingSolidarityResponse{
		Booking: &proto.BookingSolidarity{},
	}
	resp.Booking = &proto.BookingSolidarity{
		Id: bookingRequest.ID,
		Driver: &proto.User{
			Id:               driver.Driver.ID,
			Alias:            driver.Driver.Alias,
			FirstName:        driver.Driver.FirstName,
			LastName:         driver.Driver.LastName,
			Grade:            driver.Driver.Grade,
			Picture:          driver.Driver.Picture,
			Gender:           driver.Driver.Gender,
			VerifiedIdentity: driver.Driver.VerifiedIdentity,
		},
		Passenger: &proto.User{
			Id:               passenger.Passenger.ID,
			Alias:            passenger.Passenger.Alias,
			FirstName:        passenger.Passenger.FirstName,
			LastName:         passenger.Passenger.LastName,
			Grade:            passenger.Passenger.Grade,
			Picture:          passenger.Passenger.Picture,
			Gender:           passenger.Passenger.Gender,
			VerifiedIdentity: passenger.Passenger.VerifiedIdentity,
		},
		PassengerPickupDate: &timestamp.Timestamp{
			Seconds: bookingRequest.Pickup_date,
		},
		PassengerDepartureRoute: &proto.Feature{
			Lat:     bookingRequest.Departure_address.Point().Lat(),
			Long:    bookingRequest.Departure_address.Point().Lon(),
			Address: bookingRequest.Departure_address.Properties.MustString("name"),
		},
		PassengerDestinationRoute: &proto.Feature{
			Lat:     bookingRequest.Destination_address.Point().Lat(),
			Long:    bookingRequest.Destination_address.Point().Lon(),
			Address: bookingRequest.Destination_address.Properties.MustString("name"),
		},
		Status:   ConvertInternalToProtoBookingStatus(bookingRequest.Status),
		Duration: duration,
		Distance: distance,
		Price: &proto.Price{
			Type: priceType,
		},
		Car: &proto.Car{
			Model: driver.Car.Model,
			Brand: driver.Car.Brand,
		},
	}
	return resp, nil
}

func (s *SolidarityServiceServerImpl) UpdateBookingSolidarity(ctx context.Context, req *proto.UpdateBookingSolidarityRequest) (resp *proto.UpdateBookingSolidarityResponse, err error) {
	if req.BookingId == "" || req.Status.String() == "" {
		return &proto.UpdateBookingSolidarityResponse{
			Success: false,
		}, errors.New("missing required fields")
	}
	bookingStatus := internal.BookingStatus(req.Status.String())
	err = s.Handler.UpdateBooking(context.Background(), req.BookingId, bookingStatus)
	if err != nil {
		if strings.Contains(err.Error(), utils.SQL_NO_ROWS) {
			err = errors.New("invalid ID")
		}
		return &proto.UpdateBookingSolidarityResponse{
			Success: false,
		}, err
	}
	return &proto.UpdateBookingSolidarityResponse{
		Success: true,
	}, nil
}

func (s *SolidarityServiceServerImpl) GetBookingSolidarity(ctx context.Context, req *proto.GetBookingSolidarityRequest) (resp *proto.GetBookingSolidarityResponse, err error) {
	if req.BookingId == "" {
		return nil, errors.New("empty booking ID")
	}
	booking, err := s.Handler.GetBooking(context.Background(), req.BookingId)
	if err != nil {
		if strings.Contains(err.Error(), utils.SQL_NO_ROWS) {
			err = errors.New("invalid ID")
		}
		return nil, err
	}
	resp = &proto.GetBookingSolidarityResponse{
		Booking: &proto.BookingSolidarity{},
	}
	priceType := proto.PriceType_FREE
	driver, err := s.Handler.GetDriver(context.Background(), booking.Driver.ID)
	if err != nil {
		return nil, err
	}
	car := driver.Car
	distance := int64(booking.Distance)
	resp.Booking = &proto.BookingSolidarity{
		Id: booking.ID,
		Driver: &proto.User{
			Id:               booking.Driver.ID,
			Alias:            booking.Driver.Alias,
			FirstName:        booking.Driver.FirstName,
			LastName:         booking.Driver.LastName,
			Grade:            booking.Driver.Grade,
			Picture:          booking.Driver.Picture,
			Gender:           booking.Driver.Gender,
			VerifiedIdentity: booking.Driver.VerifiedIdentity,
		},
		Passenger: &proto.User{
			Id:               booking.Passenger.ID,
			Alias:            booking.Passenger.Alias,
			FirstName:        booking.Passenger.FirstName,
			LastName:         booking.Passenger.LastName,
			Grade:            booking.Passenger.Grade,
			Picture:          booking.Passenger.Picture,
			Gender:           booking.Passenger.Gender,
			VerifiedIdentity: booking.Passenger.VerifiedIdentity,
		},
		PassengerPickupDate: &timestamp.Timestamp{
			Seconds: booking.Pickup_date,
		},
		PassengerDepartureRoute: &proto.Feature{
			Lat:     booking.PassengerPickupAddress.Point().Lat(),
			Long:    booking.PassengerPickupAddress.Point().Lon(),
			Address: booking.PassengerPickupAddress.Properties.MustString("name"),
		},
		PassengerDestinationRoute: &proto.Feature{
			Lat:     booking.PassengerDropAddress.Point().Lat(),
			Long:    booking.PassengerDropAddress.Point().Lon(),
			Address: booking.PassengerDropAddress.Properties.MustString("name"),
		},
		Status:   ConvertInternalToProtoBookingStatus(booking.Status),
		Duration: booking.Duration,
		Distance: distance,
		Car: &proto.Car{
			Model: car.Model,
			Brand: car.Brand,
		},
		Price: &proto.Price{
			Type: priceType,
		},
	}
	return resp, nil

}
func (s *SolidarityServiceServerImpl) GetBookingsByStatus(ctx context.Context, req *proto.GetBookingsByStatusRequest) (resp *proto.GetBookingsByStatusResponse, err error) {
	if req.Type.String() == "" || req.Status.String() == "" || req.UserId == "" {
		return nil, errors.New("missing required fields")
	}

	bookings, err := s.Handler.GetBookingsByStatus(ctx, req.Status.String(), req.Type.String(), req.UserId)
	if err != nil {
		if strings.Contains(err.Error(), utils.SQL_NO_ROWS) {
			return nil, errors.New("invalid ID")
		}
		return nil, err
	}

	// Use a goroutine to concurrently convert bookings to proto
	respChan := make(chan []*proto.BookingSolidarity, 1)
	go func() {
		respChan <- convertInternalBookingsToProto(s, bookings, 50)
	}()

	select {
	case convertedBookings := <-respChan:
		close(respChan)

		resp = &proto.GetBookingsByStatusResponse{
			Booking: convertedBookings,
		}
		return resp, nil

	case <-ctx.Done():
		// If the context is canceled, return an error
		return nil, ctx.Err()
	}
}

func convertInternalBookingsToProto(s *SolidarityServiceServerImpl, bookings []internal.Booking, maxGoroutines int) []*proto.BookingSolidarity {
	var responses []*proto.BookingSolidarity
	var wg sync.WaitGroup
	var mu sync.Mutex
	semaphore := make(chan struct{}, maxGoroutines)

	for _, v := range bookings {
		wg.Add(1)
		semaphore <- struct{}{}

		go func(booking internal.Booking) {
			defer func() {
				<-semaphore
				wg.Done()
			}()

			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()

			var driver internal.Driver
			var driverErr error
			driverCh := make(chan struct {
				Driver internal.Driver
				Err    error
			})

			go func() {
				d, err := s.Handler.GetDriver(ctx, booking.Driver.ID)
				driverCh <- struct {
					Driver internal.Driver
					Err    error
				}{Driver: d, Err: err}
			}()

			driverRes := <-driverCh
			driver = driverRes.Driver
			driverErr = driverRes.Err

			if driverErr != nil {
				log.Error().Err(driverErr).Msg("Error getting driver")
				return
			}

			car := driver.Car

			priceType := proto.PriceType_FREE
			distance := int64(booking.Distance)
			protoBooking := &proto.BookingSolidarity{
				Id:        booking.ID,
				Status:    ConvertInternalToProtoBookingStatus(booking.Status),
				Driver:    convertInternalUserToProtoUser(driver.Driver),
				Passenger: convertInternalUserToProtoUser(booking.Passenger),
				PassengerPickupDate: &timestamp.Timestamp{
					Seconds: booking.Pickup_date,
				},
				PassengerDepartureRoute:   convertInternalFeatureToProtoFeature(booking.PassengerPickupAddress),
				PassengerDestinationRoute: convertInternalFeatureToProtoFeature(booking.PassengerDropAddress),
				Duration:                  booking.Duration,
				Distance:                  distance,
				Car: &proto.Car{
					Model: car.Model,
					Brand: car.Brand,
				},
				Price: &proto.Price{
					Type: priceType,
				},
			}

			// Use a mutex to safely append to the responses slice
			mu.Lock()
			responses = append(responses, protoBooking)
			mu.Unlock()
		}(v)
	}

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

	close(semaphore)

	return responses
}

func convertInternalUserToProtoUser(user internal.User) *proto.User {
	return &proto.User{
		Id:               user.ID,
		Alias:            user.Alias,
		FirstName:        user.FirstName,
		LastName:         user.LastName,
		Grade:            user.Grade,
		Picture:          user.Picture,
		Gender:           user.Gender,
		VerifiedIdentity: user.VerifiedIdentity,
	}
}

func convertInternalFeatureToProtoFeature(feature *geojson.Feature) *proto.Feature {
	return &proto.Feature{
		Lat:     feature.Point().Lat(),
		Long:    feature.Point().Lon(),
		Address: feature.Properties.MustString("name"),
	}
}

func (s *SolidarityServiceServerImpl) DriverJourneys(ctx context.Context, req *proto.DriverJourneysRequest) (resp *proto.DriverJourneysResponse, err error) {
	if req.DepartureDate.Seconds == 0 || req.Departure == nil {
		return nil, errors.New("missing required fields")
	}
	drivers, err := s.Handler.GetDriverJourneys(context.Background(), &geojson.Feature{
		Type:     "Feature",
		Geometry: orb.Geometry(orb.Point{req.Departure.Lat, req.Departure.Long}),
		Properties: geojson.Properties{
			"name": req.Departure.Address,
		}},
		req.DepartureDate.Seconds)
	if err != nil {
		return nil, err
	}
	resp = &proto.DriverJourneysResponse{
		DriverJourneys: []*proto.DriverJourney{},
	}
	response := []*proto.DriverJourney{}
	for _, v := range drivers {
		temp := &proto.DriverJourney{}
		if v.AvailabilitiesType == internal.Regular && v.RegularAvailabilities != nil {
			regularAvailabilities := make([]*proto.RegularAvailabilitySlot, 0) // Initialize an empty slice
			for _, v := range v.RegularAvailabilities {
				day := ConvertToProtoDayOfTheWeek(v.DayOfWeek)
				regularAvailabilities = append(regularAvailabilities, &proto.RegularAvailabilitySlot{
					DayOfWeek: day,
					StartTime: v.StartTime,
					EndTime:   v.EndTime,
				})
			}
			convertedAvailability := &proto.RepeatedRegularAvailabilitySlot{
				RegularAvailabilities: regularAvailabilities,
			}
			temp.Availabilities = &proto.DriverJourney_RepeatedRegularAvailabilities{
				RepeatedRegularAvailabilities: convertedAvailability,
			}

		} else if v.AvailabilitiesType == internal.Punctual && v.PunctualAvailabilities != nil {
			punctualAvailabilities := make([]*proto.PunctualAvailabilitySlot, 0) // Initialize an empty slice
			for _, v := range v.PunctualAvailabilities {
				punctualAvailabilities = append(punctualAvailabilities, &proto.PunctualAvailabilitySlot{
					Date: &timestamp.Timestamp{
						Seconds: v.Date,
					},
					StartTime: v.StartTime,
					EndTime:   v.EndTime,
				})
			}
			convertedAvailability := &proto.RepeatedPunctualAvailabilitySlot{
				PunctualAvailabilities: punctualAvailabilities,
			}

			temp.Availabilities = &proto.DriverJourney_RepeatedPunctualAvailabilities{
				RepeatedPunctualAvailabilities: convertedAvailability,
			}
		}
		priceType := proto.PriceType_FREE
		tamp := &proto.DriverJourney{
			User: &proto.User{
				Id:               v.Driver.ID,
				Alias:            v.Driver.Alias,
				FirstName:        v.Driver.FirstName,
				LastName:         v.Driver.LastName,
				Grade:            v.Driver.Grade,
				Picture:          v.Driver.Picture,
				Gender:           v.Driver.Gender,
				VerifiedIdentity: v.Driver.VerifiedIdentity,
			},
			Car: &proto.Car{
				Model: v.Car.Model,
				Brand: v.Car.Brand,
			},
			DriverDeparture_Date: &timestamp.Timestamp{
				Seconds: req.DepartureDate.Seconds,
			},
			Price: &proto.Price{
				Type: priceType,
			},
			DriverDeparture_Address: v.Driver_departure_address.Properties.MustString("name"),
		}
		temp.DriverDeparture_Address = tamp.DriverDeparture_Address
		temp.Car = tamp.Car
		temp.User = tamp.User
		temp.DriverDeparture_Date = tamp.DriverDeparture_Date
		temp.Price = tamp.Price
		response = append(response, temp)
	}
	resp.DriverJourneys = response
	return resp, nil
}
func (s *SolidarityServiceServerImpl) SetPassengerTrip(ctx context.Context, req *proto.PassengerTripRequest) (resp *proto.PassengerTripResponse, err error) {
	if req.Passenger.Id == "" || req.Passenger.Alias == "" {
		return &proto.PassengerTripResponse{
			Success: false,
		}, errors.New("missing required fields")
	}
	passenger := internal.Passenger{}
	passenger.Passenger.ID = req.Passenger.Id
	passenger.Passenger.Alias = req.Passenger.Alias
	if req.Passenger.FirstName != "" {
		passenger.Passenger.FirstName = req.Passenger.FirstName
	}
	if req.Passenger.LastName != "" {
		passenger.Passenger.LastName = req.Passenger.LastName
	}
	if req.Passenger.Grade != 0 {
		passenger.Passenger.Grade = req.Passenger.Grade
	}
	if req.Passenger.Picture != "" {
		passenger.Passenger.Picture = req.Passenger.Picture
	}
	if req.Passenger.Gender != "" {
		passenger.Passenger.Gender = req.Passenger.Gender
	}
	if req.Passenger.VerifiedIdentity != false {
		passenger.Passenger.VerifiedIdentity = req.Passenger.VerifiedIdentity
	}
	if req.Preferences != nil {
		passenger.Preferences = internal.Preferences{
			Smoking:      req.Preferences.Smoking,
			Animals:      req.Preferences.Animals,
			Music:        req.Preferences.Music,
			Is_talker:    req.Preferences.IsTalker,
			Luggage_size: req.Preferences.LuggageSize,
		}
	}

	err = s.Handler.SetPassengerTrip(context.Background(), passenger)
	if err != nil {
		return &proto.PassengerTripResponse{
			Success: false,
		}, err
	}
	return &proto.PassengerTripResponse{
		Success: true,
	}, nil

}
