package knowledgeqa

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
	"github.com/tidbcloud/AgentTeam/internal/store/serviceactor"
)

const (
	DefinitionID   = "svcdef_agentteam_knowledge_assistant"
	DefinitionSlug = "agentteam-knowledge-assistant"
	DisplayName    = "Knowledge Assistant"
	Handle         = "knowledge-assistant"
	Version        = "1.0.0"
	IdentityID     = "agentteam.knowledge_assistant"
)

type Provisioner struct {
	db     coredb.DB
	actors *serviceactor.Store
}

func NewProvisioner(db coredb.DB) *Provisioner {
	return &Provisioner{db: db, actors: serviceactor.New(db)}
}

// EnsureWorkspace materializes one non-mentionable service author per
// workspace. It has only message.write authority and is never projected as an
// Agent, Agent Member, DM peer, assignee, or mention target.
func (provisioner *Provisioner) EnsureWorkspace(ctx context.Context, workspaceID, creatorMemberID string, now time.Time) (model.RuntimeAppInstallation, error) {
	if provisioner == nil || provisioner.db == nil || provisioner.actors == nil {
		return model.RuntimeAppInstallation{}, fmt.Errorf("knowledge assistant provisioner is not configured")
	}
	workspaceID = strings.TrimSpace(workspaceID)
	creatorMemberID = strings.TrimSpace(creatorMemberID)
	if workspaceID == "" || creatorMemberID == "" {
		return model.RuntimeAppInstallation{}, fmt.Errorf("workspace and creator member are required")
	}
	if now.IsZero() {
		now = time.Now().UTC()
	} else {
		now = now.UTC()
	}
	var result model.RuntimeAppInstallation
	err := coredb.WithTx(ctx, provisioner.db, func(tx coredb.Tx) error {
		actors := provisioner.actors.InTx(tx)
		memberID := deterministicID("mem", "knowledge-assistant-member", workspaceID)
		if err := actors.EnsureServiceMemberSubstrate(ctx, serviceactor.ServiceMemberSubstrateInsert{
			ID: memberID, WorkspaceID: workspaceID, DisplayName: DisplayName, Now: now,
		}); err != nil {
			return err
		}
		installation, err := actors.UpsertInstallation(ctx, serviceactor.InstallationUpsert{
			ID:          deterministicID("appinst", "knowledge-assistant-installation", workspaceID),
			WorkspaceID: workspaceID, ServiceDefinitionID: DefinitionID,
			ServiceKind: serviceactor.KindApp, InstanceKey: serviceactor.DefaultInstanceKey,
			Status: serviceactor.StatusActive, InstalledVersion: Version,
			Config: []byte(`{}`), Metadata: []byte(`{"builtin":true,"identity":"agentteam.knowledge_assistant","version":"1.0.0"}`),
			CreatedByMemberID: creatorMemberID, CreatedByActorType: "internal_service",
			CreatedByActorID: IdentityID, Now: now,
		})
		if err != nil {
			return err
		}
		member, err := actors.UpsertMember(ctx, serviceactor.MemberUpsert{
			ID:          deterministicID("svcmem", "knowledge-assistant-service-member", workspaceID),
			WorkspaceID: workspaceID, ServiceDefinitionID: DefinitionID,
			ServiceInstallationID: installation.ID, MemberID: memberID,
			ServiceKind: serviceactor.KindApp, Handle: Handle, DisplayName: DisplayName,
			Status: serviceactor.StatusActive, Now: now,
		})
		if err != nil {
			return err
		}
		if err := actors.SyncGrantScopes(ctx, installation, creatorMemberID, []string{"messages.write"}, now); err != nil {
			return err
		}
		result = model.RuntimeAppInstallation{
			InstallationID: installation.ID,
			AppID:          DefinitionID, AppSlug: DefinitionSlug, AppName: DisplayName,
			AppKind: serviceactor.KindApp, MemberID: member.MemberID, Handle: Handle,
			WorkspaceID: workspaceID, Config: []byte(`{}`),
		}
		return nil
	})
	return result, err
}

func deterministicID(prefix, namespace string, parts ...string) string {
	payload := namespace
	for _, part := range parts {
		payload += "\x00" + strings.TrimSpace(part)
	}
	sum := sha256.Sum256([]byte(payload))
	return prefix + "_" + hex.EncodeToString(sum[:16])
}
