package graph

import (
	"strconv"
	"time"

	"gogs.dmsc.dev/arp/graph/model"
	"gogs.dmsc.dev/arp/models"
)

// ID helpers for converting between string IDs (GraphQL) and uint IDs (database)
func toID(s string) (uint, error) {
	id, err := strconv.ParseUint(s, 10, 32)
	return uint(id), err
}

// convertUser converts models.User to model.User
func convertUser(u models.User) *model.User {
	roles := make([]*model.Role, len(u.Roles))
	for i, r := range u.Roles {
		roles[i] = &model.Role{
			ID:          strconv.FormatUint(uint64(r.ID), 10),
			Name:        r.Name,
			Description: r.Description,
			Permissions: convertPermissions(r.Permissions),
		}
	}
	return &model.User{
		ID:        strconv.FormatUint(uint64(u.ID), 10),
		Email:     u.Email,
		Roles:     roles,
		CreatedAt: u.CreatedAt.String(),
		UpdatedAt: u.UpdatedAt.String(),
	}
}

// convertUsers converts []models.User to []*model.User
func convertUsers(users []models.User) []*model.User {
	result := make([]*model.User, len(users))
	for i, u := range users {
		result[i] = convertUser(u)
	}
	return result
}

// convertNote converts models.Note to model.Note
func convertNote(n models.Note) *model.Note {
	userID := strconv.FormatUint(uint64(n.UserID), 10)
	serviceID := strconv.FormatUint(uint64(n.ServiceID), 10)

	var user *model.User
	if n.User.ID > 0 {
		user = convertUser(n.User)
	}

	var service *model.Service
	if n.Service.ID > 0 {
		service = convertService(n.Service)
	}

	return &model.Note{
		ID:        strconv.FormatUint(uint64(n.ID), 10),
		Title:     n.Title,
		Content:   n.Content,
		UserID:    userID,
		User:      user,
		ServiceID: serviceID,
		Service:   service,
		CreatedAt: n.CreatedAt.String(),
		UpdatedAt: n.UpdatedAt.String(),
	}
}

// convertNotes converts []models.Note to []*model.Note
func convertNotes(notes []models.Note) []*model.Note {
	result := make([]*model.Note, len(notes))
	for i, n := range notes {
		result[i] = convertNote(n)
	}
	return result
}

// convertRole converts models.Role to model.Role
func convertRole(r models.Role) *model.Role {
	permissions := make([]*model.Permission, len(r.Permissions))
	for i, p := range r.Permissions {
		permissions[i] = &model.Permission{
			ID:          strconv.FormatUint(uint64(p.ID), 10),
			Code:        p.Code,
			Description: p.Description,
		}
	}
	return &model.Role{
		ID:          strconv.FormatUint(uint64(r.ID), 10),
		Name:        r.Name,
		Description: r.Description,
		Permissions: permissions,
	}
}

// convertRoles converts []models.Role to []*model.Role
func convertRoles(roles []models.Role) []*model.Role {
	result := make([]*model.Role, len(roles))
	for i, r := range roles {
		result[i] = convertRole(r)
	}
	return result
}

// convertPermission converts models.Permission to model.Permission
func convertPermission(p models.Permission) *model.Permission {
	return &model.Permission{
		ID:          strconv.FormatUint(uint64(p.ID), 10),
		Code:        p.Code,
		Description: p.Description,
	}
}

// convertPermissions converts []models.Permission to []*model.Permission
func convertPermissions(perms []models.Permission) []*model.Permission {
	result := make([]*model.Permission, len(perms))
	for i, p := range perms {
		result[i] = convertPermission(p)
	}
	return result
}

// convertService converts models.Service to model.Service
func convertService(s models.Service) *model.Service {
	var desc *string
	if s.Description != "" {
		desc = &s.Description
	}
	createdByID := strconv.FormatUint(uint64(s.CreatedByID), 10)
	participants := make([]*model.User, len(s.Participants))
	for i, u := range s.Participants {
		participants[i] = convertUser(u)
	}
	tasks := make([]*model.Task, len(s.Tasks))
	for i, t := range s.Tasks {
		tasks[i] = convertTask(t)
	}
	return &model.Service{
		ID:           strconv.FormatUint(uint64(s.ID), 10),
		Name:         s.Name,
		Description:  desc,
		CreatedByID:  createdByID,
		CreatedBy:    convertUser(s.CreatedBy),
		Participants: participants,
		Tasks:        tasks,
		CreatedAt:    s.CreatedAt.String(),
		UpdatedAt:    s.UpdatedAt.String(),
	}
}

// convertServices converts []models.Service to []*model.Service
func convertServices(services []models.Service) []*model.Service {
	result := make([]*model.Service, len(services))
	for i, s := range services {
		result[i] = convertService(s)
	}
	return result
}

// convertTaskStatus converts models.TaskStatus to model.TaskStatus
func convertTaskStatus(ts models.TaskStatus) *model.TaskStatus {
	tasks := make([]*model.Task, len(ts.Tasks))
	for i, t := range ts.Tasks {
		tasks[i] = convertTask(t)
	}
	return &model.TaskStatus{
		ID:        strconv.FormatUint(uint64(ts.ID), 10),
		Code:      ts.Code,
		Label:     ts.Label,
		Tasks:     tasks,
		CreatedAt: ts.CreatedAt.String(),
		UpdatedAt: ts.UpdatedAt.String(),
	}
}

// convertTaskStatuses converts []models.TaskStatus to []*model.TaskStatus
func convertTaskStatuses(statuses []models.TaskStatus) []*model.TaskStatus {
	result := make([]*model.TaskStatus, len(statuses))
	for i, ts := range statuses {
		result[i] = convertTaskStatus(ts)
	}
	return result
}

// convertTask converts models.Task to model.Task
func convertTask(t models.Task) *model.Task {
	var dueDate *string
	if t.DueDate != nil {
		formatted := t.DueDate.Format(time.RFC3339)
		dueDate = &formatted
	}
	var statusID *string
	var status *model.TaskStatus
	if t.Status.ID > 0 {
		sid := strconv.FormatUint(uint64(t.StatusID), 10)
		statusID = &sid
		status = convertTaskStatus(t.Status)
	}
	var assigneeID *string
	var assignee *model.User
	if t.AssigneeID != nil && t.Assignee != nil {
		aid := strconv.FormatUint(uint64(*t.AssigneeID), 10)
		assigneeID = &aid
		assignee = convertUser(*t.Assignee)
	}
	return &model.Task{
		ID:          strconv.FormatUint(uint64(t.ID), 10),
		Title:       t.Title,
		Content:     t.Content,
		CreatedByID: strconv.FormatUint(uint64(t.CreatedByID), 10),
		CreatedBy:   convertUser(t.CreatedBy),
		UpdatedByID: strconv.FormatUint(uint64(t.UpdatedByID), 10),
		UpdatedBy:   convertUser(t.UpdatedBy),
		AssigneeID:  assigneeID,
		Assignee:    assignee,
		StatusID:    statusID,
		Status:      status,
		DueDate:     dueDate,
		Priority:    t.Priority,
		CreatedAt:   t.CreatedAt.String(),
		UpdatedAt:   t.UpdatedAt.String(),
	}
}

// convertTasks converts []models.Task to []*model.Task
func convertTasks(tasks []models.Task) []*model.Task {
	result := make([]*model.Task, len(tasks))
	for i, t := range tasks {
		result[i] = convertTask(t)
	}
	return result
}

// convertMessage converts models.Message to model.Message
func convertMessage(m models.Message) *model.Message {
	receivers := make([]string, len(m.Receivers))
	receiverObjects := make([]*model.User, len(m.Receivers))
	for i, r := range m.Receivers {
		receivers[i] = strconv.FormatUint(uint64(r.ID), 10)
		receiverObjects[i] = convertUser(r)
	}
	return &model.Message{
		ID:              strconv.FormatUint(uint64(m.ID), 10),
		SenderID:        strconv.FormatUint(uint64(m.SenderID), 10),
		Sender:          convertUser(m.Sender),
		Content:         m.Content,
		SentAt:          m.SentAt.String(),
		Receivers:       receivers,
		ReceiverObjects: receiverObjects,
		CreatedAt:       m.CreatedAt.String(),
		UpdatedAt:       m.UpdatedAt.String(),
	}
}

// convertMessages converts []models.Message to []*model.Message
func convertMessages(messages []models.Message) []*model.Message {
	result := make([]*model.Message, len(messages))
	for i, m := range messages {
		result[i] = convertMessage(m)
	}
	return result
}

// convertWorkflowTemplate converts models.WorkflowTemplate to model.WorkflowTemplate
func convertWorkflowTemplate(w models.WorkflowTemplate) *model.WorkflowTemplate {
	var createdBy *model.User
	if w.CreatedBy.ID > 0 {
		createdBy = convertUser(w.CreatedBy)
	}
	return &model.WorkflowTemplate{
		ID:   strconv.FormatUint(uint64(w.ID), 10),
		Name: w.Name,
		Description: func() *string {
			if w.Description != "" {
				return &w.Description
			}
			return nil
		}(),
		Definition: w.Definition,
		IsActive:   w.IsActive,
		CreatedBy:  createdBy,
		CreatedAt:  w.CreatedAt.String(),
		UpdatedAt:  w.UpdatedAt.String(),
	}
}

// convertWorkflowTemplates converts []models.WorkflowTemplate to []*model.WorkflowTemplate
func convertWorkflowTemplates(templates []models.WorkflowTemplate) []*model.WorkflowTemplate {
	result := make([]*model.WorkflowTemplate, len(templates))
	for i, w := range templates {
		result[i] = convertWorkflowTemplate(w)
	}
	return result
}

// convertWorkflowInstance converts models.WorkflowInstance to model.WorkflowInstance
func convertWorkflowInstance(w models.WorkflowInstance) *model.WorkflowInstance {
	template := convertWorkflowTemplate(w.WorkflowTemplate)
	var context *string
	if w.Context != "" {
		context = &w.Context
	}
	var service *model.Service
	if w.Service != nil && w.Service.ID > 0 {
		service = convertService(*w.Service)
	}
	var completedAt *string
	if w.CompletedAt != nil {
		completedAtVal := w.CompletedAt.String()
		completedAt = &completedAtVal
	}
	return &model.WorkflowInstance{
		ID:          strconv.FormatUint(uint64(w.ID), 10),
		Template:    template,
		Status:      w.Status,
		Context:     context,
		Service:     service,
		CreatedAt:   w.CreatedAt.String(),
		UpdatedAt:   w.UpdatedAt.String(),
		CompletedAt: completedAt,
	}
}

// convertWorkflowInstances converts []models.WorkflowInstance to []*model.WorkflowInstance
func convertWorkflowInstances(instances []models.WorkflowInstance) []*model.WorkflowInstance {
	result := make([]*model.WorkflowInstance, len(instances))
	for i, w := range instances {
		result[i] = convertWorkflowInstance(w)
	}
	return result
}

// convertWorkflowNode converts models.WorkflowNode to model.WorkflowNode
func convertWorkflowNode(n models.WorkflowNode) *model.WorkflowNode {
	var task *model.Task
	if n.Task != nil {
		task = convertTask(*n.Task)
	}
	var inputData *string
	if n.InputData != "" {
		inputData = &n.InputData
	}
	var outputData *string
	if n.OutputData != "" {
		outputData = &n.OutputData
	}
	var startedAt *string
	if n.StartedAt != nil {
		startedAtVal := n.StartedAt.String()
		startedAt = &startedAtVal
	}
	var completedAt *string
	if n.CompletedAt != nil {
		completedAtVal := n.CompletedAt.String()
		completedAt = &completedAtVal
	}
	return &model.WorkflowNode{
		ID:          strconv.FormatUint(uint64(n.ID), 10),
		NodeKey:     n.NodeKey,
		NodeType:    n.NodeType,
		Status:      n.Status,
		Task:        task,
		InputData:   inputData,
		OutputData:  outputData,
		CreatedAt:   n.CreatedAt.String(),
		UpdatedAt:   n.UpdatedAt.String(),
		StartedAt:   startedAt,
		CompletedAt: completedAt,
	}
}

// convertWorkflowNodes converts []models.WorkflowNode to []*model.WorkflowNode
func convertWorkflowNodes(nodes []models.WorkflowNode) []*model.WorkflowNode {
	result := make([]*model.WorkflowNode, len(nodes))
	for i, n := range nodes {
		result[i] = convertWorkflowNode(n)
	}
	return result
}
