package approvalapp

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/core/domain"
	"github.com/tidbcloud/AgentTeam/internal/store/app"
	"github.com/tidbcloud/AgentTeam/internal/workflow/orchestrator"
)

func pendingApprovalCardContent(request orchestrator.ApprovalRequest, currentProcessorName string) (app.AppNotificationContent, error) {
	request = request.Normalize()
	if err := request.Validate(); err != nil {
		return app.AppNotificationContent{}, err
	}
	actorPolicy := map[string]any{
		"kind":      "members",
		"memberIds": []string{request.AssigneeMemberID},
	}
	var actionInputSchema map[string]any
	if request.FeedbackScope != nil {
		actionInputSchema = workflowApprovalCommentInputSchema()
	}
	presentation := domain.NewWorkflowRunApprovalPresentation(
		"pending", request.PlanID, request.PlanVersionID, request.RunID, request.NodeID, request.Summary,
	)
	card := map[string]any{
		"schemaVersion": "1",
		"template":      "workflow_run_approval",
		"title":         "Workflow approval requested",
		"presentation":  presentation,
		"titleKey":      "workflow_run_approval_pending",
		"status":        "pending",
		"markdown":      request.Summary,
		"fields": approvalCardFields(
			request.PlanID, request.PlanVersionID, request.RunID,
			request.NodeID,
		),
		"body": approvalCardBody(
			request.PlanID, request.PlanVersionID, request.RunID,
			request.NodeID, request.Summary,
		),
		"approval": map[string]any{
			"currentProcessorNames": []string{strings.TrimSpace(currentProcessorName)},
		},
		"actions": []map[string]any{
			workflowApprovalCardAction(ActionApprove, "Approve", ActionSemanticsCommit, actorPolicy, actionInputSchema),
			workflowApprovalCardAction(ActionReject, "Reject", ActionSemanticsRevise, actorPolicy, actionInputSchema),
		},
	}
	return workflowApprovalCard(card, "Workflow approval requested: "+request.Summary)
}

func workflowApprovalCommentInputSchema() map[string]any {
	return map[string]any{
		"type": "object",
		"properties": map[string]any{
			"comment": map[string]any{"type": "string", "maxLength": orchestrator.ApprovalDecisionCommentMaxRunes},
		},
		"additionalProperties": false,
	}
}

func workflowApprovalCardAction(actionKey, label, semantics string, actorPolicy map[string]any, inputSchema map[string]any) map[string]any {
	value := map[string]any{
		"actionKey": actionKey, "type": "callback", "label": label, "semantics": semantics,
		"actorPolicy": actorPolicy,
	}
	if inputSchema != nil {
		value["inputSchema"] = inputSchema
	}
	return value
}

func resolvedApprovalCardContent(result orchestrator.ApprovalDecisionResult, processorName string) (app.AppNotificationContent, error) {
	if err := result.Validate(); err != nil {
		return app.AppNotificationContent{}, err
	}
	title, titleKey := "Workflow approval approved", "workflow_run_approval_approved"
	if result.Decision == orchestrator.ApprovalDecisionRejected {
		title, titleKey = "Workflow approval rejected", "workflow_run_approval_rejected"
	}
	body := approvalCardBody(
		result.PlanID, result.PlanVersionID, result.RunID,
		result.NodeID, result.Summary,
	)
	body["decision"] = result.Decision
	body["decidedByMemberId"] = strings.TrimSpace(result.DecidedByMemberID)
	body["decidedAt"] = result.DecidedAt.UTC().Format(timeLayout)
	presentation := domain.NewWorkflowRunApprovalPresentation(
		result.Decision, result.PlanID, result.PlanVersionID, result.RunID, result.NodeID, result.Summary,
	)
	card := map[string]any{
		"schemaVersion": "1",
		"template":      "workflow_run_approval",
		"title":         title,
		"presentation":  presentation,
		"titleKey":      titleKey,
		"status":        result.Decision,
		"markdown":      strings.TrimSpace(result.Summary),
		"fields": approvalCardFields(
			result.PlanID, result.PlanVersionID, result.RunID,
			result.NodeID,
		),
		"body": body,
		"approval": map[string]any{
			"state":         result.Decision,
			"processorName": strings.TrimSpace(processorName),
		},
	}
	return workflowApprovalCard(card, title+": "+strings.TrimSpace(result.Summary))
}

const timeLayout = "2006-01-02T15:04:05.999999999Z07:00"

func approvalCardBody(planID, planVersionID, runID, nodeID, summary string) map[string]any {
	return map[string]any{
		"planId": strings.TrimSpace(planID), "planVersionId": strings.TrimSpace(planVersionID),
		"runId": strings.TrimSpace(runID), "nodeId": strings.TrimSpace(nodeID),
		"summary": strings.TrimSpace(summary),
	}
}

func approvalCardFields(planID, planVersionID, runID, nodeID string) []map[string]any {
	return []map[string]any{
		{"label": "workflow_plan", "value": strings.TrimSpace(planID)},
		{"label": "workflow_version", "value": strings.TrimSpace(planVersionID)},
		{"label": "workflow_run", "value": strings.TrimSpace(runID)},
		{"label": "workflow_step", "value": strings.TrimSpace(nodeID)},
	}
}

func workflowApprovalCard(card map[string]any, fallback string) (app.AppNotificationContent, error) {
	presentation, ok := card["presentation"].(*domain.MessagePresentation)
	if !ok || presentation == nil {
		return app.AppNotificationContent{}, fmt.Errorf("Workflow approval card presentation is required")
	}
	if err := presentation.Validate(); err != nil {
		return app.AppNotificationContent{}, fmt.Errorf("Workflow approval card presentation is invalid: %w", err)
	}
	encoded, err := json.Marshal(card)
	if err != nil {
		return app.AppNotificationContent{}, fmt.Errorf("marshal Workflow approval card: %w", err)
	}
	return app.AppNotificationContent{
		Kind:         app.AppNotificationContentInteractiveCard,
		FallbackText: strings.TrimSpace(fallback), CardJSON: encoded,
	}, nil
}
