package prometheus

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

	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/constant"
	dtoMetrics "github.com/pingcap-inc/clinic/clinic_data_service/pkg/dto/metrics"
	"github.com/prometheus/common/model"

	confMetrics "github.com/pingcap-inc/clinic/clinic_data_service/pkg/config/metrics"
	log2 "github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	myModel "github.com/pingcap-inc/clinic/clinic_data_service/pkg/model"
	"go.uber.org/zap"
)

//func CreatePrometheusClientForMetrics(clusterId string) (*PrometheusClient, error) {
//
//	cluster := confMetrics.GetClusterByID(clusterId)
//	if cluster == nil {
//		log2.PlainError("Cluster configuration not found", zap.String("clusterId", clusterId))
//		return nil, errors.New("Cluster configuration not found")
//	}
//	if cluster.MetricsRouting == "" || cluster.Region == "" {
//		log2.PlainError("Cluster configuration missing metricsRouting or region", zap.String("clusterId", clusterId))
//		return nil, errors.New("Cluster configuration missing metricsRouting or region")
//	}
//	// Prioritize reading template from global configuration
//	prometheusURL := fmt.Sprintf(confMetrics.AppConfig.Clinic.ClusterMetricsTemplateUrl, cluster.Region, cluster.MetricsRouting)
//	pc, err := newPrometheusClient(prometheusURL)
//	if err != nil {
//		log2.PlainError("NewPrometheusClient failed", zap.Error(err))
//		return nil, err
//	}
//	return pc, nil
//}

// MetricsQueryBatch 原有批量查询函数（定时任务使用，保持不变）
// timestamp 为基准日期，Primary 为该日期前一天 00:00~23:59，Baseline 为前 14 天
func MetricsQueryBatch(ctx context.Context, cluster myModel.Cluster, queries []confMetrics.MetricsQueryConfig, timestamp time.Time) []dtoMetrics.QueryBatchResult {
	primaryEndTime := time.Date(timestamp.Year(), timestamp.Month(), timestamp.Day(), 23, 59, 59, 59, time.UTC)
	primaryStartTime := primaryEndTime.AddDate(0, 0, -1)
	baselineEndTime := primaryStartTime
	baselineStartTime := primaryEndTime.AddDate(0, 0, -14)
	return metricsQueryBatchInternal(ctx, cluster, queries, primaryStartTime, primaryEndTime, baselineStartTime, baselineEndTime)
}

// MetricsQueryBatchWithRange 支持自定义时间范围的批量查询（API 使用）
// Primary 为 startTime ~ endTime，Baseline 为 (startTime - 14天) ~ startTime
func MetricsQueryBatchWithRange(ctx context.Context, cluster myModel.Cluster, queries []confMetrics.MetricsQueryConfig, startTime, endTime time.Time) []dtoMetrics.QueryBatchResult {
	baselineEndTime := startTime
	baselineStartTime := startTime.AddDate(0, 0, -14)
	return metricsQueryBatchInternal(ctx, cluster, queries, startTime, endTime, baselineStartTime, baselineEndTime)
}

// metricsQueryBatchInternal 核心批量查询实现
func metricsQueryBatchInternal(ctx context.Context, cluster myModel.Cluster, queries []confMetrics.MetricsQueryConfig, primaryStartTime, primaryEndTime, baselineStartTime, baselineEndTime time.Time) []dtoMetrics.QueryBatchResult {
	// 创建 cluster metrics client
	var pc *PrometheusClient
	var err error
	if cluster.ClusterMetricsURL != "" {
		pc, err = CreatePrometheusClientWithUrls(ctx, cluster.ClusterMetricsURL)
	} else {
		pcReq := CreatePrometheusClientReq{
			ClusterID:  cluster.ClusterID,
			Region:     cluster.Region,
			TenantID:   cluster.OrgID,
			Provider:   cluster.Provider,
			DeployType: cluster.DeployType,
			ProjectID:  cluster.ProjectID,
		}
		pc, err = CreatePrometheusClient(ctx, pcReq)
	}
	if err != nil {
		return nil
	}

	// 创建 dataplane metrics client（仅当 URL 存在时）
	var dpPC *PrometheusClient
	if cluster.DataPlaneMetricsURL != "" {
		dpPC, err = CreatePrometheusClientWithUrls(ctx, cluster.DataPlaneMetricsURL)
		if err != nil {
			log2.Error(ctx, "Failed to create dataplane prometheus client", zap.Error(err))
			dpPC = nil
		}
	}

	results := make([]dtoMetrics.QueryBatchResult, len(queries))
	resultsChan := make(chan dtoMetrics.QueryBatchResult, len(queries))
	for i, query := range queries {
		go func(q confMetrics.MetricsQueryConfig, index int) {
			// Create base result
			queryResult := dtoMetrics.QueryBatchResult{
				Name: q.Name,
			}

			primaryQuery := strings.ReplaceAll(q.PrimaryQuery, "$rate", "4m")
			baseQuery := strings.ReplaceAll(q.PrimaryQuery, "$rate", "30m")

			// 替换 $tidb_cluster（适配 premium 集群）
			tidbClusterID := cluster.ClusterID
			if cluster.DeployType == "premium" && cluster.PhysicalClusterID != "" {
				tidbClusterID = cluster.PhysicalClusterID
			}
			primaryQuery = strings.ReplaceAll(primaryQuery, "$tidb_cluster", tidbClusterID)
			baseQuery = strings.ReplaceAll(baseQuery, "$tidb_cluster", tidbClusterID)

			// 根据查询内容选择 Prometheus client
			queryPC := pc
			if dpPC != nil && constant.IsDataPlaneQuery(q.PrimaryQuery) {
				queryPC = dpPC
				log2.Info(ctx, "Using DataPlane prometheus client", zap.String("queryName", q.Name))
			}

			primaryResult, primaryErr := queryPC.QueryRange(ctx, primaryQuery, primaryStartTime, primaryEndTime, 4*time.Minute)
			if primaryErr != nil {
				log2.Error(ctx, "Primary query failed", zap.Any("clusterId", cluster), zap.String("queryName", q.Name), zap.Error(primaryErr))
			} else {
				queryResult.PrimaryQueryResult = primaryResult
			}
			// 保存实际使用的查询语句（已替换所有占位符）
			queryResult.PrimaryQuery = primaryQuery

			var baseResult model.Value
			var baseErr error
			if q.Name == "P99QueryLatency" || q.Name == "P999QueryLatency" || q.Name == "P99TnxDuration" || q.Name == "P99TiKVLatency" {
				baseResult, baseErr = getAvgBaseLineFor14Day(ctx, queryPC, baseQuery, baselineStartTime, baselineEndTime, 30*time.Minute)
			} else {
				baseResult, baseErr = queryPC.QueryRange(ctx, baseQuery, baselineStartTime, baselineEndTime, 30*time.Minute)
			}
			if baseErr != nil {
				log2.Error(ctx, "Base line query(14 days) failed", zap.String("queryName", q.Name), zap.String("baseQuery", baseQuery), zap.String("baseStartTime", baselineStartTime.Format(time.DateTime)), zap.String("baseEndTime", baselineEndTime.Format(time.DateTime)), zap.String("step", "30m"), zap.Error(baseErr))
			} else {
				queryResult.BaseLineQueryResult = baseResult
			}

			resultsChan <- queryResult
		}(query, i)
	}

	for i := 0; i < len(queries); i++ {
		result := <-resultsChan
		results[i] = result
	}

	return results
}

func getAvgBaseLineFor14Day(ctx context.Context, pc *PrometheusClient, baseQuery string, baselineStratTime, baselineEndTime time.Time, step time.Duration) (model.Value, error) {
	// Calculate number of days
	days := int(baselineEndTime.Sub(baselineStratTime).Hours() / 24)
	if days <= 0 {
		days = 1
	}
	if days > 14 {
		days = 14
	}

	// Use Metric's string representation as key to group same time series
	type metricKey string
	seriesData := make(map[metricKey][]model.SamplePair)
	seriesMetrics := make(map[metricKey]model.Metric)

	// Query by day segments and concatenate directly
	for day := 0; day < days; day++ {
		dayStart := baselineStratTime.AddDate(0, 0, day)
		dayEnd := time.Date(dayStart.Year(), dayStart.Month(), dayStart.Day(), 23, 59, 59, 59, time.UTC)

		// Ensure it doesn't exceed end time
		if dayEnd.After(baselineEndTime) {
			dayEnd = baselineEndTime
		}

		// Query data for the day
		dayResult, err := pc.QueryRange(ctx, baseQuery, dayStart, dayEnd, step)
		if err != nil {
			log2.Warn(ctx, "Failed to query day data, skipping",
				zap.Time("dayStart", dayStart),
				zap.Time("dayEnd", dayEnd),
				zap.Error(err))
			continue
		}

		// Convert to Matrix and concatenate data points directly
		if matrix, ok := dayResult.(model.Matrix); ok {
			for _, stream := range matrix {
				key := metricKey(stream.Metric.String())
				if _, exists := seriesMetrics[key]; !exists {
					seriesMetrics[key] = stream.Metric
				}
				seriesData[key] = append(seriesData[key], stream.Values...)
			}
		}
	}

	if len(seriesData) == 0 {
		return nil, fmt.Errorf("no valid data collected from 14 days")
	}

	// Build result Matrix
	result := make(model.Matrix, 0, len(seriesData))
	for key, values := range seriesData {
		result = append(result, &model.SampleStream{
			Metric: seriesMetrics[key],
			Values: values,
		})
	}

	return result, nil
}
