package kb

import (
	"context"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/kb"
	"gorm.io/gorm"
)

func (s *KBService) ListAuditEvents(ctx context.Context, workspaceID, subject, kbID string, page, perPage int) ([]kb.AuditEvent, error) {
	if _, err := s.GetKnowledgeBase(ctx, workspaceID, subject, kbID); err != nil {
		return nil, err
	}
	page, perPage = normalizeKBPagination(page, perPage)
	return s.store.ListAuditEvents(ctx, workspaceID, kbID, page, perPage)
}

func (s *KBService) ListKBSavedViews(ctx context.Context, workspaceID string, subject string, page int, perPage int) ([]kb.KBSavedView, error) {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return nil, err
	}
	return s.store.ListKBSavedViews(ctx, strings.TrimSpace(workspaceID), strings.TrimSpace(subject), page, perPage)
}

func (s *KBService) CreateKBSavedView(ctx context.Context, workspaceID string, subject string, input KBSavedViewMutation) (kb.KBSavedView, error) {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return kb.KBSavedView{}, err
	}
	input = normalizeKBSavedViewInput(input)
	if input.Name == "" {
		return kb.KBSavedView{}, invalidArgument("KB saved view name is required")
	}
	if err := validateKBSavedView(input); err != nil {
		return kb.KBSavedView{}, err
	}
	id, err := newKBSavedViewID()
	if err != nil {
		return kb.KBSavedView{}, fmt.Errorf("generate saved view id: %w", err)
	}
	now := s.now()
	return s.store.CreateKBSavedView(ctx, kb.KBSavedView{
		ID:               id,
		WorkspaceID:      strings.TrimSpace(workspaceID),
		OwnerPrincipalID: strings.TrimSpace(subject),
		Name:             input.Name,
		Slug:             kbSlugForName(input.Name),
		Description:      input.Description,
		Filter:           input.Filter,
		Visibility:       input.Visibility,
		CreatedAt:        now,
		UpdatedAt:        now,
	})
}

func (s *KBService) UpdateKBSavedView(ctx context.Context, workspaceID string, subject string, viewID string, input KBSavedViewMutation) (kb.KBSavedView, error) {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return kb.KBSavedView{}, err
	}
	workspaceID = strings.TrimSpace(workspaceID)
	viewID = strings.TrimSpace(viewID)
	input = normalizeKBSavedViewInput(input)
	if input.Name == "" {
		return kb.KBSavedView{}, invalidArgument("KB saved view name is required")
	}
	if err := validateKBSavedView(input); err != nil {
		return kb.KBSavedView{}, err
	}
	current, err := s.store.GetKBSavedView(ctx, workspaceID, strings.TrimSpace(subject), viewID)
	if err == gorm.ErrRecordNotFound || current.OwnerPrincipalID != strings.TrimSpace(subject) {
		return kb.KBSavedView{}, notFound("KB saved view not found")
	}
	if err != nil {
		return kb.KBSavedView{}, err
	}
	current.Name = input.Name
	current.Slug = kbSlugForName(input.Name)
	current.Description = input.Description
	current.Filter = input.Filter
	current.Visibility = input.Visibility
	current.UpdatedAt = s.now()
	return s.store.UpdateKBSavedView(ctx, current)
}

func (s *KBService) DeleteKBSavedView(ctx context.Context, workspaceID string, subject string, viewID string) error {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return err
	}
	err := s.store.DeleteKBSavedView(ctx, strings.TrimSpace(workspaceID), strings.TrimSpace(subject), strings.TrimSpace(viewID))
	if err == gorm.ErrRecordNotFound {
		return notFound("KB saved view not found")
	}
	return err
}

func (s *KBService) ListKBSavedViewKnowledgeBases(ctx context.Context, workspaceID string, subject string, viewID string, page int, perPage int) (KnowledgeBaseCollectionPage, error) {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return KnowledgeBaseCollectionPage{}, err
	}
	view, err := s.store.GetKBSavedView(ctx, strings.TrimSpace(workspaceID), strings.TrimSpace(subject), strings.TrimSpace(viewID))
	if err == gorm.ErrRecordNotFound {
		return KnowledgeBaseCollectionPage{}, notFound("KB saved view not found")
	}
	if err != nil {
		return KnowledgeBaseCollectionPage{}, err
	}
	collection, query, tagIDs, err := kbSavedViewCollection(view.Filter)
	if err != nil {
		return KnowledgeBaseCollectionPage{}, err
	}
	return s.ListKnowledgeBases(ctx, workspaceID, subject, collection, query, tagIDs, page, perPage)
}

func (s *KBService) getSource(ctx context.Context, workspaceID, subject, kbID, sourceID string) (kb.Source, error) {
	if _, err := s.GetKnowledgeBase(ctx, workspaceID, subject, kbID); err != nil {
		return kb.Source{}, err
	}
	source, err := s.store.GetSource(ctx, workspaceID, kbID, sourceID)
	if err != nil {
		return kb.Source{}, mapStoreNotFound(err)
	}
	return source, nil
}

func (s *KBService) validateScope(workspaceID, subject string) error {
	if s == nil || s.store == nil {
		return invalidArgument("kb service is not configured")
	}
	if strings.TrimSpace(subject) == "" {
		return unauthorized("authenticated subject is required")
	}
	if strings.TrimSpace(workspaceID) == "" {
		return invalidArgument("workspace id is required")
	}
	return nil
}
