package tncroute

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
	"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
	"bitbucket.org/nemt/nemt-portal-api/application/tncservice"
	"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
	"bitbucket.org/nemt/nemt-portal-api/infra/auth"
	"bitbucket.org/nemt/nemt-portal-api/infra/config"
	"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
	"bitbucket.org/nemt/nemt-portal-api/server/validation"
	"github.com/labstack/echo"
	uuid "github.com/satori/go.uuid"
	"google.golang.org/api/googleapi/transport"
	urlshortener "google.golang.org/api/urlshortener/v1"

	"github.com/gorilla/websocket"
)

var (
	instance *controller
	once     sync.Once
	upgrader = websocket.Upgrader{}
)

type controller struct {
	cfg          *config.Config
	svc          *applicationservice.Service
	tnc          *tncservice.Service
	notification *notificationservice.Service
}

func controllerInstance(cfg *config.Config, svc *applicationservice.Service, tnc *tncservice.Service, notification *notificationservice.Service) *controller {
	once.Do(func() {
		instance = &controller{
			cfg:          cfg,
			svc:          svc,
			tnc:          tnc,
			notification: notification,
		}
	})
	return instance
}

func (c *controller) handleSocket(ctx echo.Context) error {
	ws, err := upgrader.Upgrade(ctx.Response(), ctx.Request(), nil)
	if err != nil {
		return err
	}
	defer ws.Close()

	for {
		// Write
		err := ws.WriteMessage(websocket.TextMessage, []byte("Hello, Client!"))
		if err != nil {
			ctx.Logger().Error(err)
		}

		// Read
		_, msg, err := ws.ReadMessage()
		if err != nil {
			ctx.Logger().Error(err)
		}
		fmt.Printf("%s\n", msg)
	}
}

func (c *controller) handleMessage(ctx echo.Context) error {
	rideID := ctx.Param("ride_uuid")
	if rideID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "rideID param is mandatory")
	}

	message := make(map[string]string)
	err := ctx.Bind(&message)
	if err != nil || message["message"] == "" {
		return routeutils.ResponseAPIValidationError(ctx, "message body param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	notifications := make([]viewmodel.Notification, 0)
	notifications = append(notifications, c.svc.Notification.GetNotification(ride, "sms", "A message to member", message["message"], false, "message"))
	notifications = append(notifications, c.svc.Notification.GetNotification(ride, "app", "A message to member", message["message"], false, "message"))

	notifications, err = c.svc.Notification.SendNotifications(notifications)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, notifications)
}

func (c *controller) getURLShortened(ride viewmodel.Ride) (string, error) {
	const (
		url = "https://portal.bcbsinstitute.com/#/ride/%s/%s"
	)

	svc, err := urlshortener.New(&http.Client{
		Transport: &transport.APIKey{Key: c.cfg.GoogleShortener.APIKey},
	})
	if err != nil {
		return "", err
	}

	userURL := fmt.Sprintf(url, ride.UUID, ride.User.ID)
	shortURL, err := svc.Url.Insert(&urlshortener.Url{
		Kind:    "urlshortener#url", // Not really needed
		LongUrl: userURL,
	}).Do()
	if err != nil {
		return "", err
	}

	return shortURL.Id, nil
}

func (c *controller) handleShare(ctx echo.Context) error {
	const (
		message = "%s shared a link with you for an upcoming ride: %s"
	)

	rideID := ctx.Param("ride_uuid")
	if rideID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "rideID param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	url, err := c.getURLShortened(ride)
	if err != nil {
		fmt.Println("Error to short url: ", err)
	}

	notifications := make([]viewmodel.Notification, 0)
	notifications = append(notifications, c.svc.Notification.GetNotification(ride, "sms", "A ride was shared with you", fmt.Sprintf(message, ride.CreatedUser.Name, url), false, "message"))
	notifications = append(notifications, c.svc.Notification.GetNotification(ride, "email", "A ride was shared with you", fmt.Sprintf(message, ride.CreatedUser.Name, url), false, "message"))
	notifications = append(notifications, c.svc.Notification.GetNotification(ride, "app", "A ride was shared with you", fmt.Sprintf(message, ride.CreatedUser.Name, url), false, "message"))

	notifications, err = c.svc.Notification.SendNotifications(notifications)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, notifications)
}

func (c *controller) handleMessageDriver(ctx echo.Context) error {
	rideID := ctx.Param("ride_uuid")
	if rideID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "rideID param is mandatory")
	}

	message := make(map[string]string)
	err := ctx.Bind(&message)
	if err != nil || message["message"] == "" {
		return routeutils.ResponseAPIValidationError(ctx, "message body param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	notifications := make([]viewmodel.Notification, 0)
	if ride.Status.Key == "accepted" || ride.Status.Key == "arrived" || ride.Status.Key == "pickedUp" {
		notifications = append(notifications, c.getDriverNotification(ride, "sms", "A message to driver", message["message"], ride.Driver.PhoneNumber, *ride.CreatedUser.PhoneNumber))
		notifications, err = c.svc.Notification.SendNotifications(notifications)
		if err != nil {
			return routeutils.HandleAPIError(ctx, err)
		}
	}
	return routeutils.ResponseAPIOK(ctx, notifications)
}

func (c *controller) handleList(ctx echo.Context) error {
	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	entity, err := c.svc.Rides.GetAll(user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ctx.Response().Header().Set("Content-Type", "application/json")
	return routeutils.ResponseAPIOK(ctx, entity)
}

func (c *controller) handle(ctx echo.Context) error {
	var requestRide viewmodel.RideRequest
	err := ctx.Bind(&requestRide)
	if err != nil {
		fmt.Println(err)
		return routeutils.ResponseAPIValidationError(ctx, "invalid parameters")
	}

	user, err := c.svc.Users.GetByUUID(requestRide.UserUUID, "US")
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	//Validate ride request
	if validationErrors := validation.ValidateRide(&requestRide, &user); len(validationErrors) > 0 {
		return routeutils.ResponseAPICustomValidationError(ctx, "ride validation failed", validationErrors)
	}

	createdUser, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	var provider viewmodel.ProviderResp
	provider, err = c.svc.Provider.GetByNPI(requestRide.RawProvider.FivePartKeyGroups[0].ProviderNum, createdUser)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	fmt.Println("Provider Found: ", provider.ProviderUUID)
	if provider.ProviderUUID == "" {
		org := viewmodel.Organization{
			Type: viewmodel.OrganizationType{
				Key:  "provider",
				Name: "Provider",
			},
			Name:        requestRide.RawProvider.OrgName,
			Description: requestRide.RawProvider.OrgName,
			Main:        false,
			Author:      createdUser,
			LastEditor:  createdUser,
			Reference:   requestRide.RawProvider,
		}

		org, err = c.svc.Organization.AddOrganization(org, createdUser)
		if err != nil {
			return routeutils.HandleAPIError(ctx, err)
		}
		fmt.Println("Organization Created: ", org.UUID)

		provider, err = c.svc.Provider.GetByOrganization(org.UUID, createdUser)
		if err != nil {
			return routeutils.HandleAPIError(ctx, err)
		}
		fmt.Println("Provider Found: ", provider.ProviderUUID)
	}
	requestRide.Provider = provider
	requestRide.Destination.ID = provider.MukID

	name := user.Name
	names := strings.Split(name, " ")
	requestRide.Passenger.FirstName = names[0]
	requestRide.Passenger.LastName = " "
	requestRide.Passenger.PhoneNumber = *user.PhoneNumber

	var resp viewmodel.RideRequest
	if requestRide.TripType.Key != "from_visit_call" {
		if requestRide.TripType.Key == "from_visit" {
			newOrigin := requestRide.Origin
			requestRide.Origin = requestRide.Destination
			requestRide.Destination = newOrigin
		}

		if createdUser.Test {
			resp, err = c.tnc.Lyft.RequestRide(requestRide)
		} else {
			fmt.Println("In Production")
			resp, err = c.tnc.LyftProd.RequestRide(requestRide)
		}
		if err != nil {
			return routeutils.HandleAPIError(ctx, err)
		}

		if requestRide.TripType.Key == "from_visit" {
			newOrigin := resp.Origin
			resp.Origin = resp.Destination
			resp.Destination = newOrigin
		}

		resp.RideID = strings.Replace(resp.RideID, "s_", "", -1)
	} else {
		resp = requestRide

		UUID, _ := uuid.NewV4()
		resp.RideID = UUID.String()
	}

	if resp.Status == "scheduled" || requestRide.TripType.Key == "from_visit_call" {
		if requestRide.PickupTime == nil {
			currentDate := time.Now()
			requestRide.PickupTime = &currentDate
		}
		requestMS := (requestRide.PickupTime.UnixNano() / int64(time.Millisecond))
		generateDate := time.Now()
		generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
		resp.RequestAt = requestRide.PickupTime
		resp.RequestAtMS = &requestMS
		resp.GeneratedAt = &generateDate
		resp.GeneratedAtMS = &generateMS
	}

	resp.Passenger.FirstName = names[0]
	resp.Passenger.LastName = names[len(names)-1]
	resp.Passenger.PhoneNumber = *user.PhoneNumber

	if resp.Passenger.ImageURL == nil {
		imageURL := " "
		resp.Passenger.ImageURL = &imageURL
	}

	resp.UserUUID = requestRide.UserUUID

	if requestRide.TripType.Key == "from_visit" {
		resp.Origin.Name = requestRide.Destination.Name
		resp.Origin.ID = requestRide.Provider.MukID
		resp.Destination.Name = requestRide.Origin.Name
		resp.Destination.ID = requestRide.Origin.ID
	} else {
		resp.Origin.Name = requestRide.Origin.Name
		resp.Origin.ID = requestRide.Origin.ID
		resp.Destination.Name = requestRide.Destination.Name
		resp.Destination.ID = requestRide.Provider.MukID
	}

	resp.Distance = requestRide.Distance
	resp.Duration = requestRide.Duration
	resp.ETA = requestRide.ETA
	resp.PickupTime = requestRide.PickupTime
	resp.VisitDate = requestRide.VisitDate
	resp.VisitTime = requestRide.VisitTime
	resp.VisitExternalID = requestRide.VisitExternalID
	resp.CreateUserUUID = createdUser.ID
	resp.Visit.TripType = requestRide.TripType

	if resp.TripType.Key == "from_visit_call" {
		resp.Status = "willCall"
		resp.Passenger.UserID = &resp.UserUUID
	}

	resp.TripType.Key = requestRide.TripType.Key
	if requestRide.TripType.Key == "roundtrip" || requestRide.TripType.Key == "roundtrip_call" {
		resp.TripType.Key = "to_visit"
	} else if requestRide.TripType.Key == "from_visit_call" {
		resp.TripType.Key = "from_visit_call"
	}

	entity, err := c.svc.Rides.Save(resp)
	if err != nil {
		fmt.Println("Error to save rides: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	go func() {
		err = c.svc.Notification.SendNotification(resp.Status, entity, resp)
		if err != nil {
			fmt.Println("Error to notify user: ", err.Error())
		}
	}()

	if requestRide.TripType.Key == "roundtrip" || requestRide.TripType.Key == "roundtrip_call" {
		newRide := requestRide

		if requestRide.TripType.Key == "roundtrip" {
			destination := newRide.Origin
			newRide.Origin = newRide.Destination
			newRide.Destination = destination
			if requestRide.ReturnTime != nil {
				newRide.PickupTime = requestRide.ReturnTime
			}

			scheduledRide := make(map[string]interface{})
			scheduledRide["timestamp_ms"] = requestRide.PickupTime.Unix()
			newRide.ScheduledPickupRange = scheduledRide

			newRide.Passenger.FirstName = names[0]
			newRide.Passenger.LastName = " "
			newRide.Passenger.PhoneNumber = *user.PhoneNumber

			if createdUser.Test {
				newRide, err = c.tnc.Lyft.RequestRide(newRide)
			} else {
				fmt.Println("In Production")
				newRide, err = c.tnc.LyftProd.RequestRide(newRide)
			}
			if err != nil {
				return routeutils.HandleAPIError(ctx, err)
			}

			destination = newRide.Origin
			newRide.Origin = newRide.Destination
			newRide.Destination = destination

			if newRide.Error != "" {
				fmt.Println("Error to schedule a ride on lyft: ", newRide.Error, newRide.ErrorDescription)
			} else {
				fmt.Println("Ride Scheduled: ", newRide.Status)
			}

			newRide.TripType.Key = "from_visit"
		} else {
			newRide.TripType.Key = "from_visit_call"
			newRide.Status = "willCall"
			newRide.RideID = entity.UUID
		}

		newRide.Visit = entity.Visit
		newRide.PickupTime = requestRide.ReturnTime

		requestMS := (newRide.PickupTime.UnixNano() / int64(time.Millisecond))
		generateDate := time.Now()
		generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
		newRide.RequestAt = newRide.PickupTime
		newRide.RequestAtMS = &requestMS
		newRide.GeneratedAt = &generateDate
		newRide.GeneratedAtMS = &generateMS

		newRide.Passenger.FirstName = names[0]
		newRide.Passenger.LastName = names[len(names)-1]
		newRide.Passenger.PhoneNumber = *user.PhoneNumber
		newRide.Passenger.UserID = &requestRide.UserUUID

		if newRide.Passenger.ImageURL == nil {
			imageURL := " "
			newRide.Passenger.ImageURL = &imageURL
		}

		newRide.UserUUID = requestRide.UserUUID
		newRide.Origin.Name = requestRide.Destination.Name
		newRide.Origin.ID = requestRide.Destination.ID
		newRide.Destination.Name = requestRide.Origin.Name
		newRide.Destination.ID = requestRide.Origin.ID
		newRide.Distance = requestRide.Distance
		newRide.Duration = requestRide.Duration
		newRide.ETA = requestRide.ETA
		newRide.VisitDate = requestRide.VisitDate
		newRide.VisitTime = requestRide.VisitTime
		newRide.VisitExternalID = requestRide.VisitExternalID
		newRide.CreateUserUUID = createdUser.ID

		roudtripRide, err := c.svc.Rides.Save(newRide)
		if err != nil {
			return routeutils.HandleAPIError(ctx, err)
		}

		go func() {
			err = c.svc.Notification.SendNotification(newRide.Status, roudtripRide, newRide)
			if err != nil {
				fmt.Println("Error notifying user: ", err.Error())
			}
		}()
	}

	ctx.Response().Header().Set("Content-Type", "application/json")
	return routeutils.ResponseAPIOK(ctx, entity)
}

func (c *controller) getDriverNotification(ride viewmodel.Ride, notificationType string, subject string, message string, to string, from string) viewmodel.Notification {
	retVal := viewmodel.Notification{
		Type:        notificationType,
		Message:     message,
		Subject:     subject,
		Ride:        ride,
		User:        ride.User,
		CreatedUser: ride.CreatedUser,
		To:          to,
		From:        from,
	}

	return retVal
}

func (c *controller) handleRawLyft(ctx echo.Context) error {
	rideUUID := ctx.Param("ride_uuid")
	if rideUUID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "ride_uuid param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideUUID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	var lyftRide viewmodel.RideRequest
	if user.Test {
		lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
	} else {
		fmt.Println("In Production")
		lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
	}
	if err != nil {
		fmt.Println("Error getting lyft details: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, lyftRide)
}

func (c *controller) handleRideETA(ctx echo.Context) error {
	rideUUID := ctx.Param("ride_uuid")
	if rideUUID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "ride_uuid param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideUUID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if ride.Status.Key == "accepted" || ride.Status.Key == "pickedUp" || ride.Status.Key == "arrived" {
		var lyftRide viewmodel.RideRequest
		if user.Test {
			lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
		} else {
			fmt.Println("In Production")
			lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
		}
		if err != nil {
			fmt.Println("Error getting lyft details: ", err.Error())
			return routeutils.HandleAPIError(ctx, err)
		}

		ride.Route.Location = ride.Route.Origin
		ride.Route.Location.Address = ""
		ride.Route.Location.Name = ""

		switch lyftRide.Status {
		case "scheduled":
			ride.Route.ETA = ride.PickupTime.UnixNano() / int64(time.Second)
		case "accepted":
			if lyftRide.Origin.ETASeconds != nil {
				ride.Route.ETA = *lyftRide.Origin.ETASeconds
			} else {
				ride.Route.ETA = 0
				if c.cfg.App.Debug {
					ride.Route.ETA = 350
				}
			}
		case "arrived", "pickedUp":
			if lyftRide.Destination.ETASeconds != nil {
				ride.Route.ETA = *lyftRide.Destination.ETASeconds
			} else {
				ride.Route.ETA = 0
				if c.cfg.App.Debug {
					ride.Route.ETA = 350
				}
			}
		}

		if lyftRide.Location.Latitude != 0 && lyftRide.Location.Longitude != 0 {
			ride.Route.Location = lyftRide.Location
		}
	}

	return routeutils.ResponseAPIOK(ctx, ride)
}

func (c *controller) handleCancel(ctx echo.Context) error {
	var requestRide viewmodel.RideRequest
	rideUUID := ctx.Param("ride_uuid")
	if rideUUID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "ride_uuid param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideUUID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	requestRide.RideID = ride.InternalID
	if ride.Status.Key == "scheduled" && !strings.Contains(ride.InternalID, "s_") {
		requestRide.RideID = "s_" + ride.InternalID
	}

	if user.Test {
		err = c.tnc.Lyft.CancelRide(requestRide)
		if err != nil && err.Error() == "ride_not_found" {
			err = nil
		}
	} else {
		fmt.Println("In Production")
		err = c.tnc.LyftProd.CancelRide(requestRide)
	}
	if err != nil {
		fmt.Println("Error: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	err = c.svc.Rides.UpdateStatus(rideUUID, "canceled")
	if err != nil {
		fmt.Println("Error: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	// ride.Status.Key = "canceled"

	// go func() {
	// 	err = c.svc.Notification.SendNotification(ride.Status.Key, ride, viewmodel.RideRequest{})
	// 	if err != nil {
	// 		fmt.Println("Error: ", err.Error())
	// 	}
	// }()

	ctx.Response().Header().Set("Content-Type", "application/json")
	return routeutils.ResponseNoContent(ctx, nil)
}

func (c *controller) handleETA(ctx echo.Context) error {
	sLat := ctx.Param("lat")
	if sLat == "" {
		return routeutils.ResponseAPIValidationError(ctx, "lat param is mandatory")
	}

	sLog := ctx.Param("log")
	if sLog == "" {
		return routeutils.ResponseAPIValidationError(ctx, "log param is mandatory")
	}

	sDestLat := ctx.Param("destlat")
	if sLat == "" {
		return routeutils.ResponseAPIValidationError(ctx, "lat param is mandatory")
	}

	sDestLog := ctx.Param("destlong")
	if sLog == "" {
		return routeutils.ResponseAPIValidationError(ctx, "log param is mandatory")
	}

	lat, err := strconv.ParseFloat(strings.TrimSpace(sLat), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "lat invalid")
	}

	log, err := strconv.ParseFloat(strings.TrimSpace(sLog), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "log invalid")
	}

	destlat, err := strconv.ParseFloat(strings.TrimSpace(sDestLat), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "destination lat invalid")
	}

	destlog, err := strconv.ParseFloat(strings.TrimSpace(sDestLog), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "destination log invalid")
	}

	params := map[string]interface{}{}
	params["endLat"] = destlat
	params["endLng"] = destlog
	params["rideType"] = "lyft"

	resp, err := c.tnc.Lyft.GetCost(lat, log, params)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, resp)
}

func (c *controller) handleRide(ctx echo.Context) error {
	rideUUID := ctx.Param("ride_uuid")
	if rideUUID == "" {
		return routeutils.ResponseAPIValidationError(ctx, "ride_uuid param is mandatory")
	}

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideUUID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if ride.Status.Key == "accepted" || ride.Status.Key == "pickedUp" || ride.Status.Key == "arrived" {
		var lyftRide viewmodel.RideRequest
		if user.Test {
			lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
		} else {
			fmt.Println("In Production")
			lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
		}
		if err != nil {
			fmt.Println("Error getting lyft details: ", err.Error())
			return routeutils.HandleAPIError(ctx, err)
		}

		ride.Route.Location = ride.Route.Origin
		ride.Route.Location.Address = ""
		ride.Route.Location.Name = ""

		switch lyftRide.Status {
		case "scheduled":
			ride.Route.ETA = ride.PickupTime.UnixNano() / int64(time.Second)
		case "accepted":
			if lyftRide.Origin.ETASeconds != nil {
				ride.Route.ETA = *lyftRide.Origin.ETASeconds
			} else {
				ride.Route.ETA = 0
				if c.cfg.App.Debug {
					ride.Route.ETA = 350
				}
			}
		case "arrived":
			if lyftRide.Destination.ETASeconds != nil {
				ride.Route.ETA = *lyftRide.Destination.ETASeconds
			} else {
				ride.Route.ETA = 0
			}
		case "pickedUp":
			if lyftRide.Destination.ETASeconds != nil {
				ride.Route.ETA = *lyftRide.Destination.ETASeconds
			} else {
				ride.Route.ETA = 0
				if c.cfg.App.Debug {
					ride.Route.ETA = 350
				}
			}
		}

		if lyftRide.Location.Latitude != 0 && lyftRide.Location.Longitude != 0 {
			ride.Route.Location = lyftRide.Location
		}
	}

	return routeutils.ResponseAPIOK(ctx, ride)
}

func (c *controller) handleDrivers(ctx echo.Context) error {
	sLat := ctx.Param("lat")
	if sLat == "" {
		return routeutils.ResponseAPIValidationError(ctx, "lat param is mandatory")
	}

	sLog := ctx.Param("log")
	if sLog == "" {
		return routeutils.ResponseAPIValidationError(ctx, "log param is mandatory")
	}

	lat, err := strconv.ParseFloat(strings.TrimSpace(sLat), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "lat invalid")
	}

	log, err := strconv.ParseFloat(strings.TrimSpace(sLog), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "log invalid")
	}

	resp, err := c.tnc.Lyft.GetDrivers(lat, log)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, resp)
}

func (c *controller) handleTypes(ctx echo.Context) error {
	sLat := ctx.Param("lat")
	if sLat == "" {
		return routeutils.ResponseAPIValidationError(ctx, "lat param is mandatory")
	}

	sLog := ctx.Param("log")
	if sLog == "" {
		return routeutils.ResponseAPIValidationError(ctx, "log param is mandatory")
	}

	lat, err := strconv.ParseFloat(strings.TrimSpace(sLat), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "lat invalid")
	}

	log, err := strconv.ParseFloat(strings.TrimSpace(sLog), 64)
	if err != nil {
		return routeutils.ResponseAPIValidationError(ctx, "log invalid")
	}

	resp, err := c.tnc.Lyft.GetTypes(lat, log, nil)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, resp)
}

func (c *controller) handleReady(ctx echo.Context) error {
	var rideUUID = ctx.Param("ride_uuid")

	user, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	ride, err := c.svc.Rides.GetByUUID(rideUUID, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	var nextRide viewmodel.Ride
	if ride.TripType.Key == "from_visit_call" && ride.Status.Key == "willCall" {
		nextRide = ride
	} else if ride.Visit.TripType.Key == "roundtrip_call" && ride.TripType.Key == "to_visit" {
		roundTripRide, err := c.svc.Rides.GetByVisitUUIDAndTripType(ride.Visit.UUID, "from_visit_call", user)
		if err != nil {
			fmt.Println("Error to get next ride: ", err.Error())
			return routeutils.HandleAPIError(ctx, err)
		}
		nextRide = roundTripRide
	} else {
		fmt.Println("Error on get next ride ")
		return routeutils.ResponseAPINotFoundError(ctx)
	}

	var lyftRide viewmodel.RideRequest
	if user.Test {
		lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
	} else {
		fmt.Println("In Production")
		lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID})
	}
	if err != nil {
		fmt.Println("Error: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	lyftRide.RideID = ""
	lyftRide.Destination = ride.Route.Destination
	lyftRide.Origin = ride.Route.Origin

	name := nextRide.User.Name
	names := strings.Split(name, " ")
	lyftRide.Passenger.FirstName = names[0]
	lyftRide.Passenger.LastName = " "
	lyftRide.Passenger.PhoneNumber = *nextRide.User.PhoneNumber
	lyftRide.RideType = "lyft"

	if user.Test {
		lyftRide, err = c.tnc.Lyft.RequestRide(lyftRide)
	} else {
		fmt.Println("In Production")
		lyftRide, err = c.tnc.LyftProd.RequestRide(lyftRide)
	}
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	currentTime := time.Now()
	lyftRide.PickupTime = &currentTime
	lyftRide.ReturnTime = &currentTime
	nextRide.PickupTime = &currentTime

	nextRide, err = c.svc.Rides.UpdateNewRide(nextRide, lyftRide, user)
	if err != nil {
		fmt.Println("Error: ", err.Error())
		return routeutils.HandleAPIError(ctx, err)
	}

	go func() {
		err = c.svc.Notification.SendNotification(lyftRide.Status, nextRide, lyftRide)
		if err != nil {
			fmt.Println("Error to notify user: ", err.Error())
		}
	}()

	return routeutils.ResponseAPIOK(ctx, nextRide)
}
