package service

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

	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/common"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/config"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/dao"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/prometheus"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/utils"
)

func BuildHoursFromWindows(windows []TimeWindow) []string {
	// Build unique hour keys from merged windows' start/end hours (UTC)
	if len(windows) == 0 {
		return nil
	}
	hourMap := make(map[time.Time]bool)
	for _, w := range windows {
		// Normalize to hour start for both start/end
		startHour := time.Date(w.Start.Year(), w.Start.Month(), w.Start.Day(), w.Start.Hour(), 0, 0, 0, w.Start.UTC().Location())
		hourMap[startHour] = true
		endHour := time.Date(w.End.Year(), w.End.Month(), w.End.Day(), w.End.Hour(), 0, 0, 0, w.End.UTC().Location())
		if !startHour.Equal(endHour) {
			hourMap[endHour] = true
		}
	}
	var hours []string
	for h := range hourMap {
		// Format YYYYMMDDHH for S3 hour prefix
		hours = append(hours, h.Format("2006010215"))
	}
	return hours
}

func DownloadS3ForHours(ctx context.Context, clusterId string, hours []string) error {
	// Download S3 slow query logs for each hour into local path organized by day/org/cluster
	log.Info(ctx, fmt.Sprintf("Download S3 slow query logs for cluster %s  for hours %v", clusterId, hours))
	// for _, hour := range hours {
	// 	day := hour[:8]
	// 	hourStr := hour[8:]
	// 	cluster, _ := common.GetCluster(ctx, clusterId)
	// 	if cluster == nil {
	// 		log.PlainError("Cluster configuration not found in db", zap.String("clusterId", clusterId))
	// 		return errors.New("Cluster configuration not found")
	// 	}
	// 	saveDir := fmt.Sprintf("%s/%s/%s/%s", config.AppConfig.TikvInputDir, day, cluster.OrgID, clusterId)
	// 	err := s3.DownloadS3Files(clusterId, day, hourStr, saveDir)
	// 	if err != nil {
	// 		log.Error(ctx, "DownloadS3Files failed", zap.Error(err))
	// 		return err
	// 	}
	// }
	return nil
}

func AttachSlowQueryForDigests(ctx context.Context, tableName string, clusterId string, instance string, timeWindow TimeWindow, digestInfoArr []*prometheus.DigestInfo) error {
	// Attach slow query aggregation (AVG/MAX Query_time/Mem_max, COUNT) and links
	// to each digest within the given time window using local SQLite populated by S3 ingestion.
	var digests []string
	for _, d := range digestInfoArr {
		digests = append(digests, strings.ToLower(d.Digest))
	}
	if len(digests) == 0 {
		return nil
	}
	orgID, _ := common.GetOrgId(ctx, clusterId)
	dbPath := config.GetTikvDbPath(orgID)
	if !utils.FileExists(dbPath) {
		return nil
	}
	db, err := dao.InitSQLiteDB(dbPath)
	if err != nil {
		return err
	}
	startTime := timeWindow.Start.UTC().Unix()
	endTime := timeWindow.End.UTC().Unix()
	var slowQueryInfoArr []prometheus.SlowQueryInfo
	// Window-scoped aggregation query on slow query table
	sql := fmt.Sprintf(`
				SELECT 
					a.Digest, 
					ROUND(AVG(a.Mem_max), 0) AS AVGMem,
					MAX(a.Mem_max) AS MAXMem, 
					AVG(a.Query_time) AS AVGQueryTime, 
					MAX(a.Query_time) AS MAXQueryTime, 
					COUNT(*) AS TotalCount 
				 FROM %s a 
				WHERE a.Digest in (?) 
				and a.Timestamp >= ? 
				and a.Timestamp <= ? 
				and a.Cluster_Id = ? 
				GROUP BY a.Digest
				`, tableName)
	db.Raw(sql, digests, startTime, endTime, clusterId).Scan(&slowQueryInfoArr)
	for i := range digestInfoArr {
		d := digestInfoArr[i]
		// Attach TopSQL list link for the window
		topSqlLink := getTopSqlLink(ctx, clusterId, instance, timeWindow)
		d.TopSqlLink = topSqlLink
		for _, s := range slowQueryInfoArr {
			// Case-insensitive digest match
			if strings.ToUpper(s.Digest) == strings.ToUpper(d.Digest) {
				s.IsInSlowQuery = true
				d.SlowQueryInfo = s
				// Attach slow query detail/list links using max Query_time row
				req := GetDetailLinkReq{
					ClusterId:    clusterId,
					Digest:       strings.ToLower(d.Digest),
					TimeWindow:   timeWindow,
					MaxQueryTime: d.SlowQueryInfo.MAXQueryTime,
				}
				linkResp, err := getDigestLink(ctx, db, tableName, req)
				if err == nil {
					d.SlowQueryInfo.DetailLink = linkResp.DetailLink
					d.SlowQueryInfo.ListLink = linkResp.ListLink
				}
			}
		}
	}
	return nil
}
