package converter

import (
	"net/url"
	"strconv"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
)

func ToConversationPage(page message.ConversationPage) dto.ConversationPage {
	return dto.ConversationPage{
		Items:      ToConversationItems(page.Items),
		HasMore:    page.HasMore,
		NextCursor: ToConversationCursorToken(page.NextCursor),
	}
}

func ToConversationsBulkActionResponse(result message.ConversationBulkActionResult) dto.ConversationsBulkActionResponse {
	return dto.ConversationsBulkActionResponse{
		UpdatedCount: result.UpdatedCount,
	}
}

func ToConversationItems(items []message.ConversationItem) []dto.ConversationItem {
	if len(items) == 0 {
		return []dto.ConversationItem{}
	}
	converted := make([]dto.ConversationItem, 0, len(items))
	for _, item := range items {
		converted = append(converted, ToConversationItem(item))
	}
	return converted
}

func ToConversationItem(item message.ConversationItem) dto.ConversationItem {
	scopeID := strings.TrimSpace(item.ScopeID)
	kind := conversationKind(item)
	subsystem := strings.TrimSpace(item.Subsystem)
	if subsystem == message.ChannelSubsystemIM {
		subsystem = ""
	}
	return dto.ConversationItem{
		ID:                   conversationID(item),
		Kind:                 kind,
		ScopeID:              scopeID,
		Route:                InboxConversationRoute(item),
		ParentScopeID:        strings.TrimSpace(item.ParentScopeID),
		ParentScopeType:      strings.TrimSpace(item.ParentScopeType),
		ParentTitle:          strings.TrimSpace(item.ParentTitle),
		ParentMessageID:      strings.TrimSpace(item.ParentMessageID),
		ParentMessageShortID: strings.TrimSpace(item.ParentMessageShortID),
		ParentMessageAuthor:  strings.TrimSpace(item.ParentMessageAuthor),
		Title:                strings.TrimSpace(item.Title),
		Subtitle:             strings.TrimSpace(item.Subtitle),
		AvatarURL:            strings.TrimSpace(item.AvatarURL),
		Subsystem:            subsystem,
		TeamID:               strings.TrimSpace(item.TeamID),
		TeamHandle:           strings.TrimSpace(item.TeamHandle),
		TeamDisplayName:      strings.TrimSpace(item.TeamDisplayName),
		PeerType:             strings.TrimSpace(item.PeerType),
		PeerID:               strings.TrimSpace(item.PeerID),
		Preview:              strings.TrimSpace(item.Preview),
		LastAuthorName:       strings.TrimSpace(item.LastAuthorName),
		LastMessageAt:        item.LastMessageAt,
		LastActivityAt:       item.LastActivityAt,
		PinnedAt:             item.PinnedAt,
		UnreadCount:          item.UnreadCount,
		ManualUnread:         item.ManualUnread,
		SubscriptionState:    strings.TrimSpace(item.SubscriptionState),
		SidebarHidden:        item.SidebarHidden,
		Archived:             item.Archived,
		ReplyCount:           item.ReplyCount,
		LastReplyAt:          item.LastReplyAt,
		Task:                 toConversationTaskMetadata(item.Task),
	}
}

func toConversationTaskMetadata(task *message.ConversationTaskMetadata) *dto.ConversationTaskMetadata {
	if task == nil {
		return nil
	}
	return &dto.ConversationTaskMetadata{
		ID:                          strings.TrimSpace(task.ID),
		ScopeID:                     strings.TrimSpace(task.ScopeID),
		ChannelID:                   strings.TrimSpace(task.ChannelID),
		Number:                      task.Number,
		Title:                       strings.TrimSpace(task.Title),
		Status:                      strings.TrimSpace(task.Status),
		ParentTaskRef:               strings.TrimSpace(task.ParentTaskRef),
		SourceThreadID:              strings.TrimSpace(task.SourceThreadID),
		SourceThreadParentChannelID: strings.TrimSpace(task.SourceThreadParentChannelID),
		SourceThreadParentMessageID: strings.TrimSpace(task.SourceThreadParentMessageID),
		SourceThreadRef:             strings.TrimSpace(task.SourceThreadRef),
		AssigneeProfile:             ToAuthorProfile(valueOrZeroAuthorProfile(task.AssigneeProfile)),
		Route:                       strings.TrimSpace(task.Route),
	}
}

func valueOrZeroAuthorProfile(profile *message.AuthorProfile) message.AuthorProfile {
	if profile == nil {
		return message.AuthorProfile{}
	}
	return *profile
}

func conversationID(item message.ConversationItem) string {
	scopeID := strings.TrimSpace(item.ScopeID)
	if scopeID == "" {
		return ""
	}
	switch strings.TrimSpace(item.Kind) {
	case message.ConversationKindChannel:
		return "channel:" + scopeID
	case message.ConversationKindThread:
		return "thread:" + scopeID
	case message.ConversationKindDM:
		return "dm:" + scopeID
	case message.ConversationKindServiceAccount:
		return "serviceAccount:" + scopeID
	case message.ConversationKindTask:
		return "task:" + scopeID
	default:
		return scopeID
	}
}

func conversationKind(item message.ConversationItem) string {
	switch strings.TrimSpace(item.Kind) {
	case message.ConversationKindChannel:
		return "channel"
	case message.ConversationKindThread:
		return "replyThread"
	case message.ConversationKindServiceAccount:
		return "serviceAccount"
	case message.ConversationKindTask:
		return "task"
	case message.ConversationKindDM:
		switch strings.TrimSpace(item.PeerType) {
		case "human":
			return "humanDm"
		case "agent":
			return "agentDm"
		case "service":
			return "serviceDm"
		default:
			return ""
		}
	default:
		return ""
	}
}

// InboxConversationRoute returns the canonical route for an Inbox conversation
// projection. Feature-local entry points, such as the Knowledge sidebar, own
// their own contextual routes.
func InboxConversationRoute(item message.ConversationItem) string {
	scopeID := strings.TrimSpace(item.ScopeID)
	if scopeID == "" {
		return ""
	}
	encodedScopeID := url.PathEscape(scopeID)
	switch strings.TrimSpace(item.Kind) {
	case message.ConversationKindChannel:
		if strings.TrimSpace(item.Subsystem) == message.ChannelSubsystemTeam {
			teamID := firstNonEmpty(item.TeamID, item.Subtitle)
			if teamID != "" {
				return "/inbox/teams/" + url.PathEscape(teamID) + "/channel/" + encodedScopeID
			}
		}
		return "/inbox/channel/" + encodedScopeID
	case message.ConversationKindDM:
		if strings.TrimSpace(item.PeerType) == "agent" {
			peerID := strings.TrimSpace(item.PeerID)
			if peerID != "" {
				return "/inbox/agent/" + url.PathEscape(peerID)
			}
		}
		return "/inbox/dm/" + encodedScopeID
	case message.ConversationKindThread:
		if strings.EqualFold(strings.TrimSpace(item.ParentScopeType), "kb") {
			return "/inbox/kb/retrieval/thread/" + encodedScopeID
		}
		return "/inbox/thread/" + encodedScopeID
	case message.ConversationKindServiceAccount:
		accountID := strings.TrimSpace(item.PeerID)
		if accountID == "" {
			accountID = scopeID
		}
		return "/inbox/service-accounts/" + url.PathEscape(accountID)
	case message.ConversationKindTask:
		if item.Task != nil {
			channelID := strings.TrimSpace(item.Task.ChannelID)
			if channelID != "" && item.Task.Number > 0 {
				return "/inbox/tasks/" + url.PathEscape(channelID) + "/" + strconv.FormatInt(item.Task.Number, 10)
			}
			if route := strings.TrimSpace(item.Task.Route); route != "" {
				return route
			}
		}
		return ""
	default:
		return ""
	}
}
