package transformer

import (
	"eslogad-be/internal/contract"
	"eslogad-be/internal/entities"
	"math"

	"github.com/google/uuid"
)

func PaginationToRequest(page, limit int) (int, int) {
	if page < 1 {
		page = 1
	}
	if limit < 1 {
		limit = 10
	}
	if limit > 100 {
		limit = 100
	}
	return page, limit
}

func CreatePaginationResponse(totalCount, page, limit int) contract.PaginationResponse {
	totalPages := int(math.Ceil(float64(totalCount) / float64(limit)))
	if totalPages < 1 {
		totalPages = 1
	}

	return contract.PaginationResponse{
		TotalCount: totalCount,
		Page:       page,
		Limit:      limit,
		TotalPages: totalPages,
	}
}

func CreateListUsersResponse(users []contract.UserResponse, totalCount, page, limit int) *contract.ListUsersResponse {
	pagination := CreatePaginationResponse(totalCount, page, limit)
	return &contract.ListUsersResponse{
		Users:      users,
		Pagination: pagination,
	}
}

func CreateErrorResponse(message string, code int) *contract.ErrorResponse {
	return &contract.ErrorResponse{
		Error:   "error",
		Message: message,
		Code:    code,
	}
}

func CreateValidationErrorResponse(message string, details map[string]string) *contract.ValidationErrorResponse {
	return &contract.ValidationErrorResponse{
		Error:   "validation_error",
		Message: message,
		Details: details,
		Code:    400,
	}
}

func CreateSuccessResponse(message string, data interface{}) *contract.SuccessResponse {
	return &contract.SuccessResponse{
		Message: message,
		Data:    data,
	}
}

func RolesToContract(roles []entities.Role) []contract.RoleResponse {
	if roles == nil {
		return nil
	}
	res := make([]contract.RoleResponse, 0, len(roles))
	for _, r := range roles {
		res = append(res, contract.RoleResponse{ID: r.ID, Name: r.Name, Code: r.Code})
	}
	return res
}

func DepartmentsToContract(positions []entities.Department) []contract.DepartmentResponse {
	if positions == nil {
		return nil
	}
	res := make([]contract.DepartmentResponse, 0, len(positions))
	for _, p := range positions {
		res = append(res, contract.DepartmentResponse{ID: p.ID, Name: p.Name, Code: p.Code, Path: p.Path})
	}
	return res
}

func DepartmentToContract(p entities.Department) contract.DepartmentResponse {
	return contract.DepartmentResponse{ID: p.ID, Name: p.Name, Code: p.Code, Path: p.Path}
}

func ProfileEntityToContract(p *entities.UserProfile) *contract.UserProfileResponse {
	if p == nil {
		return nil
	}
	return &contract.UserProfileResponse{
		UserID:            p.UserID,
		FullName:          p.FullName,
		DisplayName:       p.DisplayName,
		Phone:             p.Phone,
		AvatarURL:         p.AvatarURL,
		JobTitle:          p.JobTitle,
		EmployeeNo:        p.EmployeeNo,
		Bio:               p.Bio,
		Timezone:          p.Timezone,
		Locale:            p.Locale,
		Preferences:       map[string]interface{}(p.Preferences),
		NotificationPrefs: map[string]interface{}(p.NotificationPrefs),
		LastSeenAt:        p.LastSeenAt,
		CreatedAt:         p.CreatedAt,
		UpdatedAt:         p.UpdatedAt,
	}
}

func ProfileUpdateToEntity(userID uuid.UUID, req *contract.UpdateUserProfileRequest, existing *entities.UserProfile) *entities.UserProfile {
	prof := &entities.UserProfile{}
	if existing != nil {
		*prof = *existing
	} else {
		prof.UserID = userID
	}
	if req.FullName != nil {
		prof.FullName = *req.FullName
	}
	if req.DisplayName != nil {
		prof.DisplayName = req.DisplayName
	}
	if req.Phone != nil {
		prof.Phone = req.Phone
	}
	if req.AvatarURL != nil {
		prof.AvatarURL = req.AvatarURL
	}
	if req.JobTitle != nil {
		prof.JobTitle = req.JobTitle
	}
	if req.EmployeeNo != nil {
		prof.EmployeeNo = req.EmployeeNo
	}
	if req.Bio != nil {
		prof.Bio = req.Bio
	}
	if req.Timezone != nil {
		prof.Timezone = *req.Timezone
	}
	if req.Locale != nil {
		prof.Locale = *req.Locale
	}
	if req.Preferences != nil {
		prof.Preferences = entities.JSONB(*req.Preferences)
	}
	if req.NotificationPrefs != nil {
		prof.NotificationPrefs = entities.JSONB(*req.NotificationPrefs)
	}
	return prof
}

func TitlesToContract(titles []entities.Title) []contract.TitleResponse {
	if titles == nil {
		return nil
	}
	out := make([]contract.TitleResponse, 0, len(titles))
	for _, t := range titles {
		out = append(out, contract.TitleResponse{
			ID:          t.ID,
			Name:        t.Name,
			Code:        t.Code,
			Description: t.Description,
		})
	}
	return out
}

func PermissionsToContract(perms []entities.Permission) []contract.PermissionResponse {
	out := make([]contract.PermissionResponse, 0, len(perms))
	for _, p := range perms {
		out = append(out, contract.PermissionResponse{
			ID:          p.ID,
			Code:        p.Code,
			Action:      p.Action,
			Description: &p.Description,
		})
	}
	return out
}

func RoleWithPermissionsToContract(role entities.Role, perms []entities.Permission) contract.RoleWithPermissionsResponse {
	return contract.RoleWithPermissionsResponse{
		ID:          role.ID,
		Name:        role.Name,
		Code:        role.Code,
		Description: &role.Description,
		Permissions: PermissionsToContract(perms),
		CreatedAt:   role.CreatedAt,
		UpdatedAt:   role.UpdatedAt,
	}
}

func LabelsToContract(list []entities.Label) []contract.LabelResponse {
	out := make([]contract.LabelResponse, 0, len(list))
	for _, e := range list {
		out = append(out, contract.LabelResponse{ID: e.ID.String(), Name: e.Name, Color: e.Color, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt})
	}
	return out
}

func PrioritiesToContract(list []entities.Priority) []contract.PriorityResponse {
	out := make([]contract.PriorityResponse, 0, len(list))
	for _, e := range list {
		out = append(out, contract.PriorityResponse{ID: e.ID.String(), Name: e.Name, Level: e.Level, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt})
	}
	return out
}

func InstitutionsToContract(list []entities.Institution) []contract.InstitutionResponse {
	out := make([]contract.InstitutionResponse, 0, len(list))
	for _, e := range list {
		out = append(out, contract.InstitutionResponse{ID: e.ID.String(), Name: e.Name, Type: string(e.Type), Address: e.Address, ContactPerson: e.ContactPerson, Phone: e.Phone, Email: e.Email, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt})
	}
	return out
}

func DispositionActionsToContract(list []entities.DispositionAction) []contract.DispositionActionResponse {
	out := make([]contract.DispositionActionResponse, 0, len(list))
	for _, e := range list {
		out = append(out, contract.DispositionActionResponse{
			ID:           e.ID.String(),
			Code:         e.Code,
			Label:        e.Label,
			Description:  e.Description,
			RequiresNote: e.RequiresNote,
			GroupName:    e.GroupName,
			SortOrder:    e.SortOrder,
			IsActive:     e.IsActive,
			CreatedAt:    e.CreatedAt,
			UpdatedAt:    e.UpdatedAt,
		})
	}
	return out
}

func DispositionRoutesToContract(list []entities.DispositionRoute) []contract.DispositionRouteResponse {
	out := make([]contract.DispositionRouteResponse, 0, len(list))
	for _, e := range list {
		var allowed map[string]interface{}
		if e.AllowedActions != nil {
			allowed = map[string]interface{}(e.AllowedActions)
		}

		resp := contract.DispositionRouteResponse{
			ID:               e.ID,
			FromDepartmentID: e.FromDepartmentID,
			ToDepartmentID:   e.ToDepartmentID,
			IsActive:         e.IsActive,
			AllowedActions:   allowed,
			CreatedAt:        e.CreatedAt,
			UpdatedAt:        e.UpdatedAt,
		}

		// Add department information if available
		if e.FromDepartment.ID != uuid.Nil {
			resp.FromDepartment = contract.DepartmentInfo{
				ID:   e.FromDepartment.ID,
				Name: e.FromDepartment.Name,
				Code: e.FromDepartment.Code,
			}
		}

		if e.ToDepartment.ID != uuid.Nil {
			resp.ToDepartment = contract.DepartmentInfo{
				ID:   e.ToDepartment.ID,
				Name: e.ToDepartment.Name,
				Code: e.ToDepartment.Code,
			}
		}

		out = append(out, resp)
	}
	return out
}
