package kb

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

	"github.com/tidbcloud/AgentTeam/internal/kbgovernance"
	storekb "github.com/tidbcloud/AgentTeam/internal/store/kb"
)

func (s *KBService) ConfigureWikiGenerationTerminalGateway(gateway kbgovernance.WikiGenerationTerminalGateway) {
	if s == nil {
		return
	}
	s.wikiTerminalMu.Lock()
	s.wikiTerminalGateway = gateway
	s.wikiTerminalMu.Unlock()
}

func (s *KBService) wikiGenerationTerminalGateway() kbgovernance.WikiGenerationTerminalGateway {
	if s == nil {
		return nil
	}
	s.wikiTerminalMu.RLock()
	defer s.wikiTerminalMu.RUnlock()
	return s.wikiTerminalGateway
}

// InspectWikiGenerationTerminal re-loads the sanitized request authority for
// AgentTeam's notification adapter. Raw worker errors remain on the Job record and
// never cross this boundary.
func (s *KBService) InspectWikiGenerationTerminal(ctx context.Context, command kbgovernance.InspectWikiGenerationTerminalCommand) (kbgovernance.WikiGenerationTerminal, error) {
	if s == nil || s.store == nil {
		return kbgovernance.WikiGenerationTerminal{}, invalidArgument("kb service is not configured")
	}
	request, err := s.store.GetGenerationRequest(ctx, strings.TrimSpace(command.WorkspaceID), strings.TrimSpace(command.RequestID))
	if err != nil {
		return kbgovernance.WikiGenerationTerminal{}, mapStoreNotFound(err)
	}
	if request.Kind != storekb.GenerationKindWiki || strings.TrimSpace(request.JobID) == "" || !wikiGenerationTerminalStatus(request.Status) || request.Version <= 0 {
		return kbgovernance.WikiGenerationTerminal{}, codedConflict("kb-wiki-generation-not-terminal", "Wiki generation request is not terminal", nil)
	}
	return kbgovernance.WikiGenerationTerminal{
		WorkspaceID: request.WorkspaceID, KnowledgeBaseID: request.KnowledgeBaseID,
		SourceID: request.SourceID, SourceRevision: request.SourceRevisionID,
		RequestID: request.ID, RequesterID: request.RequesterID,
		Status: request.Status, Reason: request.DecisionReason,
		ArtifactRevision: request.ArtifactRevision, Version: request.Version,
	}, nil
}

// ProjectPendingWikiGenerationTerminalNotifications drains a bounded durable
// projection queue. App notification creation is idempotent; acknowledging the
// exact request version after creation closes the crash window between the two
// databases.
func (s *KBService) ProjectPendingWikiGenerationTerminalNotifications(ctx context.Context, limit int, workspaceIDs []string) (int, error) {
	gateway := s.wikiGenerationTerminalGateway()
	if gateway == nil {
		return 0, nil
	}
	requests, err := s.store.ListPendingWikiGenerationTerminalNotifications(ctx, limit, workspaceIDs)
	if err != nil {
		return 0, err
	}
	projected := 0
	var projectionErr error
	for _, request := range requests {
		err := gateway.NotifyWikiGenerationTerminal(ctx, kbgovernance.NotifyWikiGenerationTerminalCommand{
			WorkspaceID: request.WorkspaceID, RequestID: request.ID, ExpectedVersion: request.Version,
		})
		if err != nil {
			projectionErr = errors.Join(projectionErr, fmt.Errorf("notify Wiki generation request %s: %w", request.ID, err))
			continue
		}
		marked, err := s.store.MarkWikiGenerationTerminalNotified(ctx, request.WorkspaceID, request.ID, request.Version, s.now())
		if err != nil {
			projectionErr = errors.Join(projectionErr, fmt.Errorf("acknowledge Wiki generation notification %s: %w", request.ID, err))
			continue
		}
		if !marked {
			current, loadErr := s.store.GetGenerationRequest(ctx, request.WorkspaceID, request.ID)
			if loadErr != nil {
				projectionErr = errors.Join(projectionErr, fmt.Errorf("reload Wiki generation notification %s after acknowledgement race: %w", request.ID, loadErr))
				continue
			}
			if current.NotificationVersion < request.Version {
				projectionErr = errors.Join(projectionErr, fmt.Errorf("acknowledge Wiki generation notification %s: projection fence was lost", request.ID))
				continue
			}
		}
		projected++
	}
	return projected, projectionErr
}

func wikiGenerationTerminalStatus(status string) bool {
	switch strings.TrimSpace(status) {
	case storekb.GenerationRequestStatusReady, storekb.GenerationRequestStatusFailed, storekb.GenerationRequestStatusStale:
		return true
	default:
		return false
	}
}

var _ kbgovernance.WikiGenerationTerminalAuthority = (*KBService)(nil)
