package services

import (
	"context"
	"errors"
	"sync"
	"time"
	"wa-assistant/backend/database"
)

type KnowledgeIndexState struct {
	Available  int
	Embedded   int
	Configured bool
	Running    bool
	Error      string
	Status     string
}

var knowledgeIndexJobs = struct {
	sync.Mutex
	running map[uint]bool
	errors  map[uint]string
}{running: map[uint]bool{}, errors: map[uint]string{}}

func KnowledgeIndexStatus(ctx context.Context, agentID uint) (KnowledgeIndexState, error) {
	items, err := LoadKnowledgeForContext(ctx, agentID)
	if err != nil {
		return KnowledgeIndexState{}, err
	}
	state := KnowledgeIndexState{Available: len(items), Configured: EmbeddingEnabled()}
	signature := embSignature()
	for _, item := range items {
		if len(item.Vec) > 0 && item.K.EmbeddingModel == knowledgeEmbeddingSignature(item.K, signature) {
			state.Embedded++
		}
	}
	knowledgeIndexJobs.Lock()
	state.Running, state.Error = knowledgeIndexJobs.running[agentID], knowledgeIndexJobs.errors[agentID]
	knowledgeIndexJobs.Unlock()
	switch {
	case !state.Configured:
		state.Status = "unconfigured"
	case state.Available == 0:
		state.Status = "empty"
	case state.Embedded == state.Available:
		state.Status = "ready"
	default:
		state.Status = "partial"
	}
	return state, nil
}

// A scoped, retryable rebuild. The existing snapshot checks discard vectors
// for rows edited/archived while the external embedding request is in flight.
func StartKnowledgeReindex(agentID uint) error {
	if !EmbeddingEnabled() {
		return errors.New("embedding_not_configured")
	}
	if database.DB == nil || agentID == 0 {
		return errors.New("knowledge_unavailable")
	}
	knowledgeIndexJobs.Lock()
	if knowledgeIndexJobs.running[agentID] {
		knowledgeIndexJobs.Unlock()
		return nil
	}
	knowledgeIndexJobs.running[agentID] = true
	knowledgeIndexJobs.errors[agentID] = ""
	knowledgeIndexJobs.Unlock()
	Go("KnowledgeReindex", func() {
		failure := ""
		defer func() {
			if recover() != nil {
				failure = "Pembaruan pencarian terhenti. Coba lagi."
			}
			knowledgeIndexJobs.Lock()
			knowledgeIndexJobs.running[agentID] = false
			knowledgeIndexJobs.errors[agentID] = failure
			knowledgeIndexJobs.Unlock()
		}()
		items, err := LoadKnowledgeForContext(context.Background(), agentID)
		if err != nil {
			failure = "Pengetahuan belum bisa dibaca. Coba lagi."
			return
		}
		deadline := time.Now().Add(10 * time.Minute)
		for _, item := range items {
			if time.Now().After(deadline) || !EmbeddingEnabled() {
				failure = "Pembaruan belum selesai. Coba lagi untuk melanjutkan pengetahuan yang tersisa."
				return
			}
			if len(item.Vec) > 0 && item.K.EmbeddingModel == knowledgeEmbeddingSignature(item.K, embSignature()) {
				continue
			}
			IndexKnowledge(&item.K)
			if item.K.Embedding == "" {
				failure = "Pembaruan belum selesai. Periksa key atau saldo penyedia, lalu coba lagi."
				return
			}
		}
		state, err := KnowledgeIndexStatus(context.Background(), agentID)
		if err != nil || state.Embedded < state.Available {
			failure = "Sebagian pengetahuan belum terindeks. Periksa key atau saldo penyedia, lalu coba lagi."
		}
	})
	return nil
}
