package builders

import (
	"encoding/json"
	"strings"

	"agent-desk/internal/models"
	"agent-desk/internal/pkg/dto/response"
	"agent-desk/internal/pkg/utils"
	"agent-desk/internal/services"
)

type TicketBuildContext struct {
	TagsByTicketID map[int64][]models.Tag
	Users          map[int64]*models.User
	Customers      map[int64]*models.Customer
}

type TicketDetailBuildContext struct {
	Users map[int64]*models.User
}

func BuildTicket(item *models.Ticket) *response.TicketResponse {
	return BuildTicketWithContext(item, nil)
}

func BuildTicketWithContext(item *models.Ticket, ctx *TicketBuildContext) *response.TicketResponse {
	if item == nil {
		return nil
	}
	ret := &response.TicketResponse{
		ID:                item.ID,
		TicketNo:          item.TicketNo,
		Title:             item.Title,
		Description:       item.Description,
		Source:            item.Source,
		Channel:           item.Channel,
		CustomerID:        item.CustomerID,
		ConversationID:    item.ConversationID,
		Status:            item.Status,
		CurrentAssigneeID: item.CurrentAssigneeID,
		CreatedBy:         item.CreateUserID,
		CreatedByName:     item.CreateUserName,
		HandledAt:         utils.FormatTimePtr(item.HandledAt),
		CreatedAt:         utils.FormatTime(item.CreatedAt),
		UpdatedAt:         utils.FormatTime(item.UpdatedAt),
	}
	if ctx != nil && ctx.TagsByTicketID != nil {
		ret.Tags = BuildTagResponses(ctx.TagsByTicketID[item.ID])
	}
	if item.CurrentAssigneeID > 0 {
		if ctx != nil && ctx.Users != nil {
			ret.CurrentAssigneeName = buildTicketUserDisplayName(ctx.Users[item.CurrentAssigneeID])
		}
	}
	if item.CustomerID > 0 {
		if ctx != nil && ctx.Customers != nil {
			ret.Customer = BuildCustomer(ctx.Customers[item.CustomerID])
		}
	}
	return ret
}

func BuildTicketList(list []models.Ticket) []response.TicketResponse {
	return BuildTicketListWithContext(list, nil)
}

func BuildTicketListWithContext(list []models.Ticket, ctx *TicketBuildContext) []response.TicketResponse {
	if len(list) == 0 {
		return nil
	}
	results := make([]response.TicketResponse, 0, len(list))
	for i := range list {
		if item := BuildTicketWithContext(&list[i], ctx); item != nil {
			results = append(results, *item)
		}
	}
	return results
}

func BuildTicketProgress(item *models.TicketProgress) *response.TicketProgressResponse {
	return BuildTicketProgressWithContext(item, nil)
}

func BuildTicketProgressWithContext(item *models.TicketProgress, ctx *TicketDetailBuildContext) *response.TicketProgressResponse {
	if item == nil {
		return nil
	}
	ret := &response.TicketProgressResponse{
		ID:        item.ID,
		TicketID:  item.TicketID,
		Content:   item.Content,
		AuthorID:  item.AuthorID,
		CreatedAt: utils.FormatTime(item.CreatedAt),
	}
	if item.AuthorID > 0 {
		if ctx != nil && ctx.Users != nil {
			ret.AuthorName = buildTicketUserDisplayName(ctx.Users[item.AuthorID])
		}
	}
	return ret
}

func BuildTicketProgressList(list []models.TicketProgress) []response.TicketProgressResponse {
	return BuildTicketProgressListWithContext(list, nil)
}

func BuildTicketProgressListWithContext(list []models.TicketProgress, ctx *TicketDetailBuildContext) []response.TicketProgressResponse {
	if len(list) == 0 {
		return nil
	}
	results := make([]response.TicketProgressResponse, 0, len(list))
	for i := range list {
		if item := BuildTicketProgressWithContext(&list[i], ctx); item != nil {
			results = append(results, *item)
		}
	}
	return results
}

func BuildTicketDetail(aggregate *services.TicketDetailAggregate) *response.TicketDetailResponse {
	if aggregate == nil || aggregate.Ticket == nil {
		return nil
	}
	ctx := &TicketBuildContext{
		TagsByTicketID: map[int64][]models.Tag{aggregate.Ticket.ID: aggregate.Tags},
		Users:          aggregate.Users,
		Customers:      map[int64]*models.Customer{},
	}
	if aggregate.Customer != nil {
		ctx.Customers[aggregate.Customer.ID] = aggregate.Customer
	}
	ret := &response.TicketDetailResponse{
		Ticket: *BuildTicketWithContext(aggregate.Ticket, ctx),
	}
	ret.Progresses = BuildTicketProgressListWithContext(aggregate.Progresses, &TicketDetailBuildContext{Users: aggregate.Users})
	return ret
}

func BuildTicketSummary(summary *services.TicketSummaryAggregate) *response.TicketSummaryResponse {
	if summary == nil {
		return nil
	}
	return &response.TicketSummaryResponse{
		All:        summary.All,
		Pending:    summary.Pending,
		InProgress: summary.InProgress,
		Done:       summary.Done,
		Unassigned: summary.Unassigned,
		Mine:       summary.Mine,
		Stale:      summary.Stale,
	}
}

func BuildTicketView(item *models.TicketView) *response.TicketViewResponse {
	if item == nil {
		return nil
	}
	ret := &response.TicketViewResponse{
		ID:     item.ID,
		Name:   item.Name,
		SortNo: item.SortNo,
	}
	if strings.TrimSpace(item.FiltersJSON) != "" {
		_ = json.Unmarshal([]byte(item.FiltersJSON), &ret.Filters)
	}
	return ret
}

func BuildTicketViewList(list []models.TicketView) []response.TicketViewResponse {
	if len(list) == 0 {
		return nil
	}
	results := make([]response.TicketViewResponse, 0, len(list))
	for i := range list {
		if item := BuildTicketView(&list[i]); item != nil {
			results = append(results, *item)
		}
	}
	return results
}

func buildTicketUserDisplayName(user *models.User) string {
	if user == nil {
		return ""
	}
	if user.Nickname != "" {
		return user.Nickname
	}
	return user.Username
}
