package approvalapp

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/app"
	"github.com/tidbcloud/AgentTeam/internal/store/approval"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
	"github.com/tidbcloud/AgentTeam/internal/store/team"
)

type workflowRunHumanMessageCreateOptions = message.HumanMessageCreateOptions
type workflowRunAppMessage = message.AppMessage
type workflowRunMessageDelivery = message.MessageDelivery
type workflowRunContributionSourceParams = message.WorkflowRunContributionSourceParams

const workflowRunHumanActorType = message.AuthorActorTypeHuman

func workflowRunContributionSource(params workflowRunContributionSourceParams) message.ContributionSource {
	return message.ContributionSourceForWorkflowRun(params)
}

type teamRoleFeedbackMessageWriter interface {
	SendAppMessageForUserWithOptions(
		context.Context,
		model.User,
		string,
		string,
		string,
		[]string,
		app.SendAppMessageOptions,
	) (message.AppMessage, message.MessageDelivery, error)
}

func (handler *Handler) postTeamRoleRejectionFeedback(
	ctx context.Context,
	payload actionEnvelope,
	result DecisionResult,
	locale string,
) error {
	instance := result.Instance
	if instance.SubjectType != SubjectTypeTeamRoleProposal ||
		instance.State != approval.StateRejected {
		return nil
	}
	if handler == nil || handler.projector == nil ||
		handler.projector.provisioner == nil || handler.projector.provisioner.db == nil {
		return fmt.Errorf("Team role rejection feedback is not configured")
	}
	writer, ok := handler.projector.notifications.(teamRoleFeedbackMessageWriter)
	if !ok {
		return fmt.Errorf("Team role rejection feedback message writer is not configured")
	}

	workspaceID := strings.TrimSpace(instance.WorkspaceID)
	teamID := strings.TrimSpace(instance.SubjectRef)
	actorUserID := strings.TrimSpace(payload.Actor.UserID)
	actorMemberID := strings.TrimSpace(payload.Actor.MemberID)
	if workspaceID == "" || teamID == "" || actorUserID == "" || actorMemberID == "" {
		return fmt.Errorf("Team role rejection feedback identity is required")
	}

	teams := team.New(handler.projector.provisioner.db)
	currentTeam, err := teams.GetTeamForUser(ctx, actorUserID, workspaceID, teamID)
	if err != nil {
		if errors.Is(err, team.ErrNotFound) {
			return nil
		}
		return fmt.Errorf("load Team for role rejection feedback: %w", err)
	}
	edges, err := teams.ExpandTeamMentionsForScope(ctx, team.ExpandTeamMentionsParams{
		WorkspaceID:    workspaceID,
		ScopeID:        currentTeam.Team.ChannelID,
		AuthorMemberID: actorMemberID,
		TeamIDs:        []string{teamID},
	})
	if err != nil {
		if errors.Is(err, team.ErrNotFound) {
			return nil
		}
		return fmt.Errorf("resolve Team leader for role rejection feedback: %w", err)
	}
	var leader *team.TeamExpansionEdge
	for index := range edges {
		edge := &edges[index]
		if edge.ActorKind != team.ActorKindAgent || edge.Role != team.MemberRoleLeader {
			continue
		}
		if leader != nil {
			return fmt.Errorf("Team role rejection feedback requires one current Team leader")
		}
		leader = edge
	}
	if leader == nil || strings.TrimSpace(leader.AgentID) == "" {
		return nil
	}
	const mentionToken = "Leader"
	leaderMention := fmt.Sprintf("[@%s](/mentions/agent/%s)", mentionToken, leader.AgentID)
	content := teamRoleRejectionFeedbackContent(leaderMention, instance.DecisionReason, locale)
	leaderRecipient := message.AgentRecipient{
		AgentID:         leader.AgentID,
		MachineID:       leader.MachineID,
		AgentMemberID:   leader.ActorID,
		AutoWakeEnabled: leader.AutoWakeEnabled,
		DeliveryReason:  message.AgentDeliveryReasonDirectMention,
		MentionToken:    mentionToken,
	}

	_, _, err = writer.SendAppMessageForUserWithOptions(
		ctx,
		model.User{ID: actorUserID},
		workspaceID,
		currentTeam.Team.ChannelID,
		content,
		nil,
		app.SendAppMessageOptions{
			ExplicitRecipients:  []message.AgentRecipient{leaderRecipient},
			ExplicitWakeTargets: []message.AgentRecipient{leaderRecipient},
			MentionHints: []message.MessageMentionHint{{
				Type:  "agent",
				ID:    leader.AgentID,
				Token: mentionToken,
			}},
			ClientMessageID:        teamRoleRejectionFeedbackClientMessageID(instance),
			ExpectedAuthorMemberID: actorMemberID,
			SkipContentModeration:  true,
		},
	)
	if err != nil {
		return fmt.Errorf("send Team role rejection feedback: %w", err)
	}
	return nil
}

func teamRoleRejectionFeedbackContent(leaderMention string, reason string, locale string) string {
	leaderMention = strings.TrimSpace(leaderMention)
	reason = strings.TrimSpace(reason)
	prefix := "The previous Team responsibility proposal was returned."
	feedbackLabel := "Feedback:"
	suffix := "Please revise the complete responsibility proposal and submit a new approval card."
	switch strings.TrimSpace(locale) {
	case "zh-CN":
		prefix = "上一版 Team 职责方案已退回。"
		feedbackLabel = "反馈："
		suffix = "请根据反馈调整完整职责方案，并重新提交一张职责审批卡。"
	case "ja":
		prefix = "前回の Team 職責案は差し戻されました。"
		feedbackLabel = "フィードバック："
		suffix = "フィードバックに基づいて完全な職責案を修正し、新しい承認カードとして再提出してください。"
	}
	if reason == "" {
		return leaderMention + " " + prefix + " " + suffix
	}
	quotedReason := "> " + strings.ReplaceAll(reason, "\n", "\n> ")
	return leaderMention + " " + prefix + "\n" + feedbackLabel + "\n" + quotedReason +
		"\n\n" + suffix
}

func teamRoleRejectionFeedbackClientMessageID(instance approval.Instance) string {
	return fmt.Sprintf(
		"team-role-proposal-rejection-feedback:%s:%d",
		strings.TrimSpace(instance.ID),
		instance.Version,
	)
}
