package qhad

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/pingcap/endless/pkg/client/tidb"
	. "github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/workloadnode/cmdstr"
	"github.com/pingcap/endless/testcase/oltp/oltppkg"
	"github.com/pingcap/endless/testcase/oltp/scenario/params"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/resource"
)

func InitializeAnalyze001Params(ctx context.Context, tidbClient *tidb.Client) (*params.Analyze, error) {
	params := params.Analyze{
		RunTime:    1 * time.Hour,
		WarmUpTime: 7 * time.Minute,
	}
	return &params, nil
}

func AnalyzePartitionsRepeatedly(
	ctx context.Context,
	tc resource.TiDBCluster,
	opts cmdstr.QHAdOptions,
) error {
	dbName := opts.DBName
	db := Try(tc.GetDB(dbName)).(*sql.DB)
	defer db.Close()
	tables := oltppkg.GetAllTablesNames(ctx, tc, dbName)
	tableNum := len(tables)
	log.Info("start truncating partition")
	for {
		select {
		case <-ctx.Done():
			log.Info("truncate ctx done.")
			return nil
		default:
		}
		for i := 0; i < tableNum; i++ {
			tableName := tables[i]
			if i%2 == 0 {
				partitionInfo, err := GetPartitionInfo(ctx, db, dbName, tableName)
				if err != nil {
					if !errors.Is(err, context.DeadlineExceeded) {
						return err
					} else {
						log.Info("GetPartitionInfo ctx done.")
						return nil
					}
				}
				partitions := partitionInfo["pName"]
				partitionsNum := len(partitions)
				for i := 0; i < partitionsNum; i++ {
					truncatePartition := fmt.Sprintf("alter table %s analyze partition %s", tableName, partitions[i])
					err := oltppkg.DbExecContextWithLog(ctx, db, truncatePartition)
					if err != nil {
						if !errors.Is(err, context.DeadlineExceeded) && !strings.Contains(err.Error(), "Unknown partition") {
							return err
						} else {
							log.Info(fmt.Sprintf("%s ctx done", truncatePartition))
							return nil
						}
					}
				}
			} else {
				truncateTable := fmt.Sprintf("analyze table %s", tableName)
				err := oltppkg.DbExecContextWithLog(ctx, db, truncateTable)
				if err != nil {
					if !errors.Is(err, context.DeadlineExceeded) && !strings.Contains(err.Error(), "Unknown partition") {
						return err
					} else {
						log.Info(fmt.Sprintf("%s ctx done", truncateTable))
						return nil
					}
				}
			}
		}
		oltppkg.WaitFor(ctx, "wait for next truncate", 20*time.Minute)
	}
}
