package server

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/config"
	"github.com/tidbcloud/AgentTeam/internal/contentpayload"
	"github.com/tidbcloud/AgentTeam/internal/core/identifiers"
	"github.com/tidbcloud/AgentTeam/internal/service/automation"
	contentstoreservice "github.com/tidbcloud/AgentTeam/internal/service/content"
	contentmigrationservice "github.com/tidbcloud/AgentTeam/internal/service/content/migration"
	kbservice "github.com/tidbcloud/AgentTeam/internal/service/kb"
	memoryservice "github.com/tidbcloud/AgentTeam/internal/service/memory"
	roleservice "github.com/tidbcloud/AgentTeam/internal/service/roles"
	skillservice "github.com/tidbcloud/AgentTeam/internal/service/skills"
	contentstorestore "github.com/tidbcloud/AgentTeam/internal/store/content"
	contentmigrationstore "github.com/tidbcloud/AgentTeam/internal/store/content/migration"
	kbstore "github.com/tidbcloud/AgentTeam/internal/store/kb"
	memorystore "github.com/tidbcloud/AgentTeam/internal/store/resource/memory"
	"github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
	rolestore "github.com/tidbcloud/AgentTeam/internal/store/resource/roles"
	skillstore "github.com/tidbcloud/AgentTeam/internal/store/resource/skills"
	"gorm.io/gorm"
)

type contentStoreRuntime struct {
	payload             contentpayload.TreePayloadBackend
	core                *contentstoreservice.Service
	role                *contentstoreservice.AuthorizedService
	skill               *contentstoreservice.AuthorizedService
	kb                  *contentstoreservice.AuthorizedService
	memory              *contentstoreservice.AuthorizedService
	automation          *contentstoreservice.AuthorizedService
	store               *contentstorestore.Store
	roleMigration       *contentmigrationservice.Worker
	skillMigration      *contentmigrationservice.Worker
	memoryMigration     *contentmigrationservice.Worker
	automationMigration *contentmigrationservice.Worker
	migrationStore      *contentmigrationstore.Store
}

// newContentStoreRuntime owns the default-off tree payload lifecycle. Enabling
// the backend does not register a generic HTTP capability or maintenance
// worker. Role, Skill, KB, and Memory retain their own live workspace and
// domain ACLs while sharing the tree core and exact authority store.
func newContentStoreRuntime(cfg config.ContentStoreConfig, database *gorm.DB, workspaceAccess agentteamCoreWorkspaceAuthorizer) (contentStoreRuntime, error) {
	if !cfg.Enabled {
		if database != nil {
			var active contentstorestore.Authority
			if err := database.WithContext(context.Background()).Model(&contentstorestore.Authority{}).
				Where("state = ?", contentstorestore.AuthorityStateNativeActive).
				Select("id").Take(&active).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
				return contentStoreRuntime{}, fmt.Errorf("check disabled Content Store native authority: %w", err)
			}
			if active.ID != "" {
				return contentStoreRuntime{}, fmt.Errorf("Content Store cannot be disabled while native authority is active")
			}
		}
		return contentStoreRuntime{}, nil
	}
	contentDB := contentstorestore.New(database)
	tree, err := openContentTreePayload(cfg.FilesystemRoot)
	if err != nil {
		return contentStoreRuntime{}, err
	}
	succeeded := false
	defer func() {
		if !succeeded {
			_ = tree.Close()
		}
	}()

	core, err := contentstoreservice.NewTree(contentDB, tree, identifiers.NewEntityID)
	if err != nil {
		return contentStoreRuntime{}, err
	}
	rolePolicy, err := roleservice.NewRoleContentAccessPolicy(workspaceAccess, rolestore.New(database))
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("role content access policy: %w", err)
	}
	role, err := contentstoreservice.NewAuthorizedService(core, rolePolicy)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("role content store service: %w", err)
	}
	skillPolicy, err := skillservice.NewSkillContentAccessPolicy(workspaceAccess, skillstore.New(database))
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("skill content access policy: %w", err)
	}
	skill, err := contentstoreservice.NewAuthorizedService(core, skillPolicy)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("skill content store service: %w", err)
	}
	kbPolicy, err := kbservice.NewKBSourceContentAccessPolicy(workspaceAccess, workspaceAccess, kbstore.New(database))
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("KB source content access policy: %w", err)
	}
	kbContent, err := contentstoreservice.NewAuthorizedService(core, kbPolicy)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("KB source content store service: %w", err)
	}
	memoryPolicy, err := memoryservice.NewMemoryContentAccessPolicy(workspaceAccess, memorystore.New(database))
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("memory content access policy: %w", err)
	}
	memory, err := contentstoreservice.NewAuthorizedService(core, memoryPolicy)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("memory content store service: %w", err)
	}
	automationPolicy, err := automation.NewAutomationContentAccessPolicy(workspaceAccess, repos.New(database), contentDB)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("automation content access policy: %w", err)
	}
	automation, err := contentstoreservice.NewAuthorizedService(core, automationPolicy)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("automation content store service: %w", err)
	}
	migrationDB := contentmigrationstore.New(database)
	roleMigration, skillMigration, memoryMigration, err := newProductContentMigrationWorkers(migrationDB, role, skill, memory)
	if err != nil {
		return contentStoreRuntime{}, err
	}
	automationWorkerID, err := identifiers.NewEntityID("cmw")
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("automation content migration worker identity: %w", err)
	}
	automationMigration, err := contentmigrationservice.NewWorker(migrationDB, automation, identifiers.NewEntityID, "automation", "automation:"+automationWorkerID, 3*time.Minute)
	if err != nil {
		return contentStoreRuntime{}, fmt.Errorf("automation content migration worker: %w", err)
	}

	succeeded = true
	return contentStoreRuntime{
		payload: tree, core: core, role: role, skill: skill, kb: kbContent, memory: memory, automation: automation, store: contentDB,
		roleMigration: roleMigration, skillMigration: skillMigration,
		memoryMigration: memoryMigration, automationMigration: automationMigration, migrationStore: migrationDB,
	}, nil
}

func newProductContentMigrationWorkers(store *contentmigrationstore.Store, role, skill, memory *contentstoreservice.AuthorizedService) (*contentmigrationservice.Worker, *contentmigrationservice.Worker, *contentmigrationservice.Worker, error) {
	contents := []*contentstoreservice.AuthorizedService{role, skill, memory}
	domains := []string{"role", "skill", "memory"}
	workers := make([]*contentmigrationservice.Worker, len(domains))
	for index, domain := range domains {
		workerID, err := identifiers.NewEntityID("cmw")
		if err != nil {
			return nil, nil, nil, fmt.Errorf("%s content migration worker identity: %w", domain, err)
		}
		workers[index], err = contentmigrationservice.NewWorker(store, contents[index], identifiers.NewEntityID, domain, domain+":"+workerID, 3*time.Minute)
		if err != nil {
			return nil, nil, nil, fmt.Errorf("%s content migration worker: %w", domain, err)
		}
	}
	return workers[0], workers[1], workers[2], nil
}
