package entitymapping

import (
	"time"

	"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
	"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)

// rideMapping has method to map ride entities to view models
type rideMapping struct {
	mapper *Mapper
}

func (mapping *rideMapping) ToRideModel(item entity.Ride) viewmodel.Ride {
	return viewmodel.Ride{
		User:        mapping.mapper.User.ToUserModel(item.User),
		Status:      mapping.ToRideStatusModel(item.Status),
		Type:        mapping.ToRideTypeModel(item.Type),
		UUID:        item.UUID,
		Note:        item.Note,
		Driver:      mapping.ToDriverUserModel(item.Driver),
		Passenger:   mapping.ToPassengerUserModel(item.Passenger),
		Vehicle:     mapping.ToVehicleModel(item.Vehicle),
		Route:       mapping.ToRouteModel(item.Route),
		PickupTime:  item.PickupTime,
		VisitDate:   item.VisitDate,
		VisitTime:   item.VisitTime,
		InternalID:  item.InternalID,
		Visit:       mapping.mapper.Visit.ToVisitModel(item.Visit),
		CreatedUser: mapping.mapper.User.ToUserModel(item.CreatedUser),
		CreateAt:    item.Created,
		UpdateAt:    item.Updated,
		TripType:    mapping.mapper.Visit.ToTripTypeModel(item.TripType),
	}
}

func (mapping *rideMapping) ToRideInternalEntity(item viewmodel.Ride) entity.Ride {
	return entity.Ride{
		User:       mapping.mapper.User.ToUserEntity(item.User),
		UUID:       item.UUID,
		Note:       item.Note,
		PickupTime: item.PickupTime,
		VisitDate:  item.VisitDate,
		VisitTime:  item.VisitTime,
		InternalID: item.InternalID,
		TripType:   mapping.mapper.Visit.ToTripTypeEntity(item.TripType),
	}
}

func (mapping *rideMapping) ToRouteModel(item entity.RideRoute) viewmodel.RideRoute {
	return viewmodel.RideRoute{
		Origin:      mapping.ToLocationModel(item.Origin),
		Destination: mapping.ToLocationModel(item.Destination),
		RouteKML:    item.RouteKML,
		ETA:         item.ETA,
		Distance:    item.Distance,
		Duration:    item.Duration,
	}
}

func (mapping *rideMapping) ToLocationModel(item entity.Location) viewmodel.Location {
	return viewmodel.Location{
		ID:        item.ID,
		Name:      item.Name,
		Address:   item.Address,
		Latitude:  item.Latitude,
		Longitude: item.Longitude,
	}
}

func (mapping *rideMapping) ToVehicleModel(item entity.RideVehicle) viewmodel.Vehicle {
	return viewmodel.Vehicle{
		Color:             item.Color,
		Make:              item.Make,
		LicensePlate:      item.LicensePlate,
		ImageURL:          item.ImageURL,
		Year:              item.Year,
		LicensePlateState: item.LicensePlateState,
		Model:             item.Model,
	}
}

func (mapping *rideMapping) ToDriverUserModel(item entity.RideDriver) viewmodel.UserLyft {
	return viewmodel.UserLyft{
		FirstName:   item.Name,
		ImageURL:    item.ImageURL,
		PhoneNumber: item.PhoneNumber,
		Rating:      item.Rating,
	}
}

func (mapping *rideMapping) ToPassengerUserModel(item entity.RidePassenger) viewmodel.UserLyft {
	return viewmodel.UserLyft{
		FirstName:   item.FirstName,
		LastName:    item.LastName,
		ImageURL:    item.ImageURL,
		PhoneNumber: item.PhoneNumber,
		UserID:      item.InternalID,
	}
}

func (mapping *rideMapping) ToRideStatusModel(item entity.RideStatus) viewmodel.RideStatus {
	return viewmodel.RideStatus{
		Value: item.Value,
		Key:   item.Key,
	}
}

func (mapping *rideMapping) ToRideTypeModel(item entity.RideType) viewmodel.RideType {
	return viewmodel.RideType{
		Value: item.Value,
		Key:   item.Key,
	}
}

func (mapping *rideMapping) ToWebhookEntity(item viewmodel.WebhookResponse) entity.WebhookResponse {
	occurredAt, _ := time.Parse(time.RFC3339Nano, item.OccurredAt)

	return entity.WebhookResponse{
		EventID:    item.EventID,
		HREF:       item.HREF,
		OccurredAt: occurredAt,
		EventType:  item.EventType,
		Ride:       mapping.ToRideEntity(item.Event),
	}
}

// ToUserModel maps a User entity to User view model
func (mapping *rideMapping) ToRideEntity(item viewmodel.RideRequest) entity.Ride {
	return entity.Ride{
		User: entity.User{
			UUID: item.UserUUID,
		},
		Status:              mapping.ToRideStatusEntity(item),
		Type:                mapping.ToRideTypeEntity(item),
		InternalID:          item.RideID,
		RequestDate:         item.RequestAt,
		RequestMiliseconds:  item.RequestAtMS,
		GenerateDate:        item.GeneratedAt,
		GenerateMiliseconds: item.GeneratedAtMS,
		Note:                item.Notes,
		PrimetimePercentage: item.PrimetimePercentage,
		Passenger:           mapping.ToRidePassengerEntity(item),
		Driver:              mapping.ToRideDriverEntity(item),
		Vehicle:             mapping.ToRideVehicleEntity(item),
		Route:               mapping.ToRideRouteEntity(item),
		PickupTime:          item.PickupTime,
		VisitDate:           item.VisitDate,
		VisitTime:           item.VisitTime,
		Visit:               mapping.mapper.Visit.ToVisitEntity(item.Visit),
		TripType:            mapping.mapper.Visit.ToTripTypeEntity(item.TripType),
		CreatedUser: entity.User{
			UUID: item.CreateUserUUID,
		},
	}
}

func (mapping *rideMapping) ToRideRouteEntity(item viewmodel.RideRequest) entity.RideRoute {
	return entity.RideRoute{
		Origin:      mapping.ToLocationEntity(item.Origin),
		Destination: mapping.ToLocationEntity(item.Destination),
		RouteKML:    &item.RouteURL,
		ETA:         item.ETA,
		Distance:    item.Distance,
		Duration:    item.Duration,
	}
}

func (mapping *rideMapping) ToLocationEntity(item viewmodel.Location) entity.Location {
	return entity.Location{
		ID:        item.ID,
		Name:      item.Name,
		Address:   item.Address,
		Latitude:  item.Latitude,
		Longitude: item.Longitude,
	}
}

func (mapping *rideMapping) ToRideVehicleEntity(item viewmodel.RideRequest) entity.RideVehicle {
	return entity.RideVehicle{
		Color:             item.Vehicle.Color,
		Make:              item.Vehicle.Make,
		LicensePlate:      item.Vehicle.LicensePlate,
		LicensePlateState: item.Vehicle.LicensePlateState,
		ImageURL:          item.Vehicle.ImageURL,
		Model:             item.Vehicle.Model,
		Year:              item.Vehicle.Year,
	}
}

func (mapping *rideMapping) ToRideDriverEntity(item viewmodel.RideRequest) entity.RideDriver {
	return entity.RideDriver{
		Name:        item.Driver.FirstName,
		ImageURL:    item.Driver.ImageURL,
		PhoneNumber: item.Driver.PhoneNumber,
		Rating:      item.Driver.Rating,
	}
}

func (mapping *rideMapping) ToRidePassengerEntity(item viewmodel.RideRequest) entity.RidePassenger {
	return entity.RidePassenger{
		FirstName:   item.Passenger.FirstName,
		LastName:    item.Passenger.LastName,
		ImageURL:    item.Passenger.ImageURL,
		PhoneNumber: item.Passenger.PhoneNumber,
		InternalID:  item.Passenger.UserID,
	}
}

func (mapping *rideMapping) ToRideStatusEntity(item viewmodel.RideRequest) entity.RideStatus {
	return entity.RideStatus{
		Key: item.Status,
	}
}

func (mapping *rideMapping) ToRideTypeEntity(item viewmodel.RideRequest) entity.RideType {
	return entity.RideType{
		Key: item.RideType,
	}
}

// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *rideMapping) ToRideEntitySlice(list []viewmodel.RideRequest) (retVal []entity.Ride) {
	retVal = make([]entity.Ride, 0)

	for _, item := range list {
		retVal = append(retVal, mapping.ToRideEntity(item))
	}

	return retVal
}

// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *rideMapping) ToRideInternalEntitySlice(list []viewmodel.Ride) (retVal []entity.Ride) {
	retVal = make([]entity.Ride, 0)

	for _, item := range list {
		retVal = append(retVal, mapping.ToRideInternalEntity(item))
	}

	return retVal
}

// ToRideModelSlice maps a Ride entity slice to Ride view model slice
func (mapping *rideMapping) ToRideModelSlice(list []entity.Ride) (retVal []viewmodel.Ride) {
	retVal = make([]viewmodel.Ride, 0)

	for _, item := range list {
		retVal = append(retVal, mapping.ToRideModel(item))
	}

	return retVal
}
