package topsqlv2

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/pingcap/log"
	"github.com/tidbcloud/observability/o11ydiagnosis/pkg/storage"
	"github.com/tidbcloud/observability/o11ydiagnosis/pkg/utils/duckdb"
	"github.com/tidbcloud/observability/o11ydiagnosis/pkg/utils/metacache"
	"go.uber.org/zap"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type DuckDBAdapter struct {
	vendor    string
	region    string
	mataCache metacache.MetaCache
	duckdb    duckdb.QueryDuckDBFetcherInterface
	store     storage.Storage
	kubeCli   client.Client
}

func NewQueryDuckDBAdapter(vendor, region string, store storage.Storage, kubeCli client.Client) *DuckDBAdapter {
	adapter := &DuckDBAdapter{
		vendor:    vendor,
		region:    region,
		mataCache: metacache.NewMetaCache(kubeCli, store),
		kubeCli:   kubeCli,
	}

	newDuckDB, err := duckdb.NewQueryDuckDBFetcherWithPool(context.Background(), vendor, region)
	if err != nil {
		log.Error("Failed to initialize DuckDB", zap.Error(err))
		panic(err)
	}
	adapter.duckdb = newDuckDB
	adapter.store = store

	// Start the warmup process in a goroutine
	// no need to warmup for pooled connection
	// go func() {
	// 	err := adapter.warmup(context.Background(), newDuckDB)
	// 	if err != nil {
	// 		log.Error("Failed to warmup DuckDB", zap.Error(err))
	// 	}
	// 	adapter.startWarmupRefreshLoop(context.Background())
	// }()
	return adapter
}

//nolint:unused // Kept for potential future use
func (s *DuckDBAdapter) startWarmupRefreshLoop(ctx context.Context) {
	// For topsql v2, no need to warmup
}

func (s *DuckDBAdapter) RenewAndWarmupDuckDB(ctx context.Context) error {
	log.Debug("Initializing DuckDB for sqls query adapter")
	defer log.Debug("DuckDB initialization completed")

	newDuckDB, err := duckdb.NewQueryDuckDBFetcherWithPool(context.Background(), s.vendor, s.region)
	if err != nil {
		log.Error("Failed to reinitialize DuckDB", zap.Error(err))
		return err
	}

	err = s.warmup(ctx, newDuckDB)
	if err != nil {
		log.Error("Failed to warmup DuckDB", zap.Error(err))
		return err
	}

	originalDuckDB := s.duckdb
	s.duckdb = newDuckDB
	if originalDuckDB != nil {
		go func() {
			time.Sleep(time.Minute * 5)
			if err := originalDuckDB.Close(context.Background()); err != nil {
				log.Error("Failed to close original DuckDB", zap.Error(err))
			} else {
				log.Info("Original DuckDB closed successfully")
			}
		}()
	}
	return nil
}

func (s *DuckDBAdapter) warmup(ctx context.Context, db duckdb.QueryDuckDBFetcherInterface) error {
	log.Debug("Starting warmup for DuckDB sqls query adapter")
	return nil
}

func tableAlias(clusterID string, table string) string {
	tableName := fmt.Sprintf("%s_%s", table, clusterID)
	return strings.ReplaceAll(tableName, "-", "_")
}

func (s *DuckDBAdapter) SelectSlowlogInDLWithoutFilterPushdown(ctx context.Context, dest interface{}, tableAlias, table, query string) error {
	return s.duckdb.SelectSlowlogInDLWithoutFilterPushdown(ctx, dest, tableAlias, table, query)
}
