package entitymapping

import (
	"fmt"
	"strings"
	"time"

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

// userMapping has method to map User entities to view models
type userMapping struct {
	mapper *Mapper
}

// ToUserModel maps a User entity to User view model
func (mapping *userMapping) ToUserModel(item entity.User) viewmodel.User {
	var birthDate *time.Time
	if !item.BirthDate.IsZero() {
		birthDate = &item.BirthDate
	}

	first := ""
	last := ""
	fullName := strings.Split(item.Name, " ")
	if len(fullName) > 0 {
		first = fullName[0]
		if len(fullName) > 1 {
			last = fullName[len(fullName)-1]
		}
	}

	return viewmodel.User{
		ID:            item.UUID,
		Name:          item.Name,
		First:         first,
		Last:          last,
		Email:         &item.Email,
		PhoneNumber:   &item.PhoneNumber,
		Gender:        &item.Gender,
		Member:        &item.Member,
		BirthDate:     birthDate,
		Active:        item.Active,
		Created:       item.Created,
		Updated:       item.Updated,
		Contacts:      mapping.ToContactModelSlice(item.Contacts),
		Rides:         mapping.mapper.Ride.ToRideModelSlice(item.Rides),
		Addresses:     mapping.mapper.Address.ToAddressModelSlice(item.Addresses),
		Profiles:      mapping.mapper.Profile.ToProfileModelSlice(item.Profiles),
		Organizations: mapping.mapper.Organization.ToOrganizationModelSlice(item.Organizations),
		Types:         mapping.mapper.Organization.ToOrganizationTypeModelSlice(item.Types),
		Type:          &item.Type,
		Test:          item.Test,
	}
}

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

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

	return retVal
}

// ToUserModel maps a User entity to User view model
func (mapping *userMapping) ToUserEntity(item viewmodel.User) entity.User {
	user := entity.User{
		UUID:          item.ID,
		Name:          item.Name,
		Pass:          item.Pass,
		Active:        item.Active,
		Created:       item.Created,
		Updated:       item.Updated,
		Contacts:      mapping.ToContactEntitySlice(item.Contacts),
		Profiles:      mapping.mapper.Profile.ToProfileEntitySlice(item.Profiles),
		Organizations: mapping.mapper.Organization.ToOrganizationEntitySlice(item.Organizations),
		Types:         mapping.mapper.Organization.ToOrganizationTypeEntitySlice(item.Types),
		Test:          item.Test,
	}

	if item.Type == nil {
		user.Type = "S"
	} else {
		user.Type = *item.Type
	}

	if user.Name == "" {
		user.Name = fmt.Sprintf("%s %s", item.First, item.Last)
	}

	if item.Email != nil {
		user.Email = *item.Email
	}

	if item.PhoneNumber != nil {
		user.PhoneNumber = *item.PhoneNumber
	}

	if item.Gender != nil {
		user.Gender = *item.Gender
	}

	if item.Member != nil {
		user.Member = *item.Member
	}

	if item.BirthDate != nil {
		user.BirthDate = *item.BirthDate
	}

	return user
}

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

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

	return retVal
}

// ToContactTypeEntity maps a Contact type entity to Contact Type view model
func (mapping *userMapping) ToContactTypeEntity(item viewmodel.ContactType) entity.ContactType {
	return entity.ContactType{
		Key:   item.Key,
		Value: item.Value,
	}
}

// ToContactTypeEntitySlice maps a User entity slice to Contact Type view model slice
func (mapping *userMapping) ToContactTypeEntitySlice(list []viewmodel.ContactType) (retVal []entity.ContactType) {
	retVal = make([]entity.ContactType, 0)

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

	return retVal
}

// ToContactTypeModel maps a Contact type entity to Contact Type view model
func (mapping *userMapping) ToContactTypeModel(item entity.ContactType) viewmodel.ContactType {
	return viewmodel.ContactType{
		Key:   item.Key,
		Value: item.Value,
	}
}

// ToContactTypeModelSlice maps a User entity slice to Contact Type view model slice
func (mapping *userMapping) ToContactTypeModelSlice(list []entity.ContactType) (retVal []viewmodel.ContactType) {
	retVal = make([]viewmodel.ContactType, 0)

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

	return retVal
}

// ToContactModel maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact {
	return viewmodel.Contact{
		ID:     item.UUID,
		User:   mapping.ToUserModel(item.User),
		Author: mapping.ToUserModel(item.Author),
		Type:   mapping.ToContactTypeModel(item.Type),
		Value:  item.Value,
	}
}

// ToContactModelSlice maps a Contact entity slice to Contact view model slice
func (mapping *userMapping) ToContactModelSlice(list []entity.ContactInfo) (retVal []viewmodel.Contact) {
	retVal = make([]viewmodel.Contact, 0)

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

	return retVal
}

// ToContactEntity maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo {
	return entity.ContactInfo{
		UUID:   item.ID,
		User:   mapping.ToUserEntity(item.User),
		Author: mapping.ToUserEntity(item.Author),
		Type:   mapping.ToContactTypeEntity(item.Type),
		Value:  item.Value,
	}
}

// ToContactEntitySlice maps a Contact entity slice to Contact view model slice
func (mapping *userMapping) ToContactEntitySlice(list []viewmodel.Contact) (retVal []entity.ContactInfo) {
	retVal = make([]entity.ContactInfo, 0)

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

	return retVal
}
