package approvalapp

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/kbgovernance"
	"github.com/tidbcloud/AgentTeam/internal/store/app"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

// WikiGenerationTerminalGateway projects MeshX's durable terminal requests
// through AgentTeam's Approval App without turning direct Admin generation into an
// Approval instance.
type WikiGenerationTerminalGateway struct {
	authority kbgovernance.WikiGenerationTerminalAuthority
	members   wikiGenerationMembers
	projector *Projector
}

func NewWikiGenerationTerminalGateway(authority kbgovernance.WikiGenerationTerminalAuthority, db coredb.DB, projector *Projector) *WikiGenerationTerminalGateway {
	return &WikiGenerationTerminalGateway{authority: authority, members: coreWikiGenerationMembers{db: db}, projector: projector}
}

func (gateway *WikiGenerationTerminalGateway) NotifyWikiGenerationTerminal(ctx context.Context, command kbgovernance.NotifyWikiGenerationTerminalCommand) error {
	if gateway == nil || gateway.authority == nil || gateway.members == nil || gateway.projector == nil || gateway.projector.notifications == nil || gateway.projector.provisioner == nil {
		return fmt.Errorf("Wiki generation terminal notification gateway is not configured")
	}
	command.WorkspaceID, command.RequestID = strings.TrimSpace(command.WorkspaceID), strings.TrimSpace(command.RequestID)
	if command.WorkspaceID == "" || command.RequestID == "" || command.ExpectedVersion <= 0 {
		return fmt.Errorf("Wiki generation terminal notification identity is invalid")
	}
	terminal, err := gateway.authority.InspectWikiGenerationTerminal(ctx, kbgovernance.InspectWikiGenerationTerminalCommand{
		WorkspaceID: command.WorkspaceID, RequestID: command.RequestID,
	})
	if err != nil {
		return err
	}
	if err := validateWikiGenerationTerminal(terminal, command); err != nil {
		return err
	}
	memberID, err := gateway.members.ResolveMember(ctx, terminal.WorkspaceID, terminal.RequesterID)
	if err != nil {
		// A requester who left the workspace is no longer an addressable Human.
		// Suppression is terminal; transient database failures still retry.
		if errors.Is(err, storeerr.ErrForbidden) {
			return nil
		}
		return err
	}
	if _, err := gateway.projector.provisioner.EnsureWorkspace(ctx, terminal.WorkspaceID, time.Now().UTC()); err != nil {
		return err
	}
	content, err := wikiGenerationTerminalContent(terminal)
	if err != nil {
		return err
	}
	_, err = gateway.projector.notifications.CreateAppNotificationForBuiltin(ctx, IdentityID, terminal.WorkspaceID, app.AppNotificationCommand{
		ClientNotificationID: wikiGenerationTerminalClientNotificationID(terminal.RequestID),
		Target:               app.AppNotificationTarget{Kind: app.AppNotificationTargetHumanDM, MemberID: memberID},
		Content:              content,
		BusinessObject: app.AppNotificationBusinessObject{
			Namespace: BusinessNamespace, Type: BusinessTypeWikiGenerationRequest,
			ID: terminal.RequestID, Version: terminal.Version,
			URL: wikiGenerationURL(terminal.KnowledgeBaseID, terminal.SourceID),
		},
		RecipientBasis: app.AppNotificationRecipientBasis{Kind: RecipientBasisWikiGenerationRequester, Ref: terminal.RequesterID},
		CorrelationID:  "kb-wiki-generation-terminal:" + terminal.RequestID,
	})
	return err
}

func validateWikiGenerationTerminal(terminal kbgovernance.WikiGenerationTerminal, command kbgovernance.NotifyWikiGenerationTerminalCommand) error {
	if terminal.WorkspaceID != command.WorkspaceID || terminal.RequestID != command.RequestID || terminal.Version != command.ExpectedVersion ||
		strings.TrimSpace(terminal.KnowledgeBaseID) == "" || strings.TrimSpace(terminal.SourceID) == "" ||
		strings.TrimSpace(terminal.SourceRevision) == "" || strings.TrimSpace(terminal.RequesterID) == "" {
		return fmt.Errorf("Wiki generation terminal notification authority does not match")
	}
	switch terminal.Status {
	case kbgovernance.WikiGenerationTerminalReady:
		if strings.TrimSpace(terminal.ArtifactRevision) == "" || strings.TrimSpace(terminal.Reason) != "" {
			return fmt.Errorf("ready Wiki generation terminal is invalid")
		}
	case kbgovernance.WikiGenerationTerminalFailed, kbgovernance.WikiGenerationTerminalStale:
		if strings.TrimSpace(terminal.Reason) == "" || strings.TrimSpace(terminal.ArtifactRevision) != "" {
			return fmt.Errorf("unsuccessful Wiki generation terminal is invalid")
		}
		if !wikiGenerationTerminalReasonAllowed(terminal.Status, terminal.Reason) {
			return fmt.Errorf("Wiki generation terminal reason is invalid")
		}
	default:
		return fmt.Errorf("Wiki generation terminal status is invalid")
	}
	return nil
}

func wikiGenerationTerminalReasonAllowed(status, reason string) bool {
	reason = strings.TrimSpace(reason)
	if status == kbgovernance.WikiGenerationTerminalFailed {
		return reason == "generation_failed"
	}
	switch reason {
	case "source_revision_changed", "authorization_changed", "knowledge_base_unavailable":
		return true
	default:
		return false
	}
}

func wikiGenerationTerminalContent(terminal kbgovernance.WikiGenerationTerminal) (app.AppNotificationContent, error) {
	title, titleKey := "Wiki 生成失败", "kb_wiki_generation_failed"
	if terminal.Status == kbgovernance.WikiGenerationTerminalReady {
		title, titleKey = "Wiki 已生成", "kb_wiki_generation_ready"
	} else if terminal.Status == kbgovernance.WikiGenerationTerminalStale {
		title, titleKey = "Wiki 生成申请已失效", "kb_wiki_generation_stale"
	}
	fields := []map[string]any{
		{"label": "knowledge_base_id", "value": terminal.KnowledgeBaseID},
		{"label": "source_id", "value": terminal.SourceID},
		{"label": "source_revision", "value": terminal.SourceRevision},
	}
	if terminal.ArtifactRevision != "" {
		fields = append(fields, map[string]any{"label": "artifact_revision", "value": terminal.ArtifactRevision})
	}
	if terminal.Reason != "" {
		fields = append(fields, map[string]any{"label": "reason", "value": terminal.Reason})
	}
	card := map[string]any{
		"schemaVersion": "1", "template": "default", "title": title, "titleKey": titleKey,
		"status": terminal.Status, "fields": fields,
		"actions": []map[string]any{{
			"actionKey": "open_wiki_setup", "type": "open_url", "label": "打开 Wiki 设置",
			"semantics": ActionSemanticsNavigate, "url": wikiGenerationURL(terminal.KnowledgeBaseID, terminal.SourceID),
		}},
	}
	encoded, err := json.Marshal(card)
	if err != nil {
		return app.AppNotificationContent{}, fmt.Errorf("marshal Wiki generation terminal notification: %w", err)
	}
	return app.AppNotificationContent{Kind: app.AppNotificationContentInteractiveCard, FallbackText: title, CardJSON: encoded}, nil
}

func wikiGenerationTerminalClientNotificationID(requestID string) string {
	return "kb-wiki-generation:" + strings.TrimSpace(requestID) + ":terminal"
}

var _ kbgovernance.WikiGenerationTerminalGateway = (*WikiGenerationTerminalGateway)(nil)
