package approvalapp

import (
	"context"
	"fmt"
	"strings"

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

func resolveKBGovernanceNotification(
	ctx context.Context,
	projector *Projector,
	installationID, clientID string,
	content app.AppNotificationContent,
	instance approval.Instance,
	mutationPrefix string,
	presentation PresentationContext,
	subjectLabel string,
) (app.AppNotificationResult, bool, error) {
	record, found, err := projector.notifications.FindAppNotificationByClientID(ctx, instance.WorkspaceID, installationID, clientID)
	if err != nil || !found {
		return app.AppNotificationResult{}, found, err
	}
	if record.ClientNotificationID != clientID || record.ContentKind != app.AppNotificationContentInteractiveCard ||
		record.BusinessObjectNamespace == nil || *record.BusinessObjectNamespace != BusinessNamespace ||
		record.BusinessObjectType == nil || *record.BusinessObjectType != BusinessTypeInstance ||
		record.BusinessObjectID == nil || *record.BusinessObjectID != instance.ID {
		return app.AppNotificationResult{}, false, fmt.Errorf("%s Approval notification authority does not match", subjectLabel)
	}
	if record.Status == app.AppNotificationStatusResolved {
		current, err := projector.notifications.GetAppNotificationForBuiltin(ctx, IdentityID, instance.WorkspaceID, record.ID)
		return current, true, err
	}
	if record.Status != app.AppNotificationStatusActive {
		return app.AppNotificationResult{}, false, fmt.Errorf("%s Approval notification cannot resolve from status %q", subjectLabel, record.Status)
	}
	version := instance.Version
	command := app.AppNotificationMutationCommand{
		NotificationID: record.ID, Kind: app.AppNotificationMutationResolve,
		ExpectedRevision: record.Revision, ClientMutationID: mutationPrefix + ":" + fmt.Sprint(instance.Version),
		Content: &content, BusinessObjectVersion: &version,
		CausedByActor: kbApprovalTerminalActor(instance), CorrelationID: instance.CorrelationID,
	}
	if record.ID == strings.TrimSpace(presentation.NotificationID) {
		if strings.TrimSpace(presentation.DeliveryID) == "" || strings.TrimSpace(presentation.AttemptID) == "" || strings.TrimSpace(presentation.MutationID) == "" {
			return app.AppNotificationResult{}, false, fmt.Errorf("%s Approval action projection context is incomplete", subjectLabel)
		}
		actionPrefix := strings.ToLower(strings.ReplaceAll(subjectLabel, " ", "-"))
		command.ClientMutationID = actionPrefix + "-action:" + strings.TrimSpace(presentation.MutationID) + ":" + record.ID
		resolved, err := projector.notifications.MutateAppNotificationForBuiltinDelivery(ctx, IdentityID, instance.WorkspaceID, presentation.DeliveryID, presentation.AttemptID, command)
		return resolved, true, err
	}
	resolved, err := projector.notifications.MutateAppNotificationForBuiltin(ctx, IdentityID, instance.WorkspaceID, command)
	return resolved, true, err
}

func validateKBGovernanceAssignment(subjectLabel string, instance approval.Instance, assignment approval.Assignment, expectedStatus string) error {
	if assignment.WorkspaceID != instance.WorkspaceID || assignment.ApprovalInstanceID != instance.ID ||
		strings.TrimSpace(assignment.ID) == "" || strings.TrimSpace(assignment.ApproverMemberID) == "" || assignment.Status != expectedStatus {
		return fmt.Errorf("%s Approval notification assignment is invalid", subjectLabel)
	}
	return nil
}

func kbApprovalTerminalAssignmentStatus(instance approval.Instance, assignment approval.Assignment) string {
	if assignment.Status == approval.AssignmentSuperseded {
		return assignment.Status
	}
	switch instance.State {
	case approval.StateApproved:
		if assignment.Status == approval.AssignmentApproved || assignment.Status == approval.AssignmentCancelled {
			return assignment.Status
		}
	case approval.StateRejected:
		if assignment.Status == approval.AssignmentRejected || assignment.Status == approval.AssignmentCancelled {
			return assignment.Status
		}
	case approval.StateCancelled:
		if assignment.Status == approval.AssignmentCancelled {
			return assignment.Status
		}
	}
	return ""
}

func kbApprovalNotificationBusinessObject(instance approval.Instance, path string) app.AppNotificationBusinessObject {
	return app.AppNotificationBusinessObject{Namespace: BusinessNamespace, Type: BusinessTypeInstance, ID: instance.ID, Version: instance.Version, URL: path}
}

func kbApprovalTerminalActor(instance approval.Instance) app.AppNotificationActorRef {
	memberID := strings.TrimSpace(instance.DecidedByMemberID)
	if memberID == "" {
		memberID = instance.ApplicantMemberID
	}
	return app.AppNotificationActorRef{Type: "human", ID: memberID}
}
