package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	clinic_internal_api "github.com/pingcap-inc/clinic/clinic_data_service/pkg/clinic-internal-api"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/config"
	myerr "github.com/pingcap-inc/clinic/clinic_data_service/pkg/errors"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/service"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/thirdapi/aws"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/utils"
	"go.uber.org/zap"
)

// SlowQueryHandler 慢查询分析 HTTP 处理器
type SlowQueryHandler struct {
	analyzer     *service.SlowQueryAnalyzer
	config       *config.DataProxyConfig
	clinicClient *clinic_internal_api.Client
}

// NewSlowQueryHandler 创建处理器实例
func NewSlowQueryHandler(analyzer *service.SlowQueryAnalyzer, cfg *config.DataProxyConfig) *SlowQueryHandler {
	return &SlowQueryHandler{
		analyzer:     analyzer,
		config:       cfg,
		clinicClient: clinic_internal_api.NewClient(cfg.ClinicAPIBase),
	}
}

// HealthCheckAnalyze 健康检查慢查询分析接口（替换原有 /slowquery/analyze）
// POST /healthcheck/sql/slowquery-analyze
func (h *SlowQueryHandler) HealthCheckAnalyze(c *gin.Context) {

	ctx := c.Request.Context()
	log.Info(ctx, "HealthCheck SlowQuery Analysis started", zap.String("env", config.AppConfig.Env))
	var req service.AnalyzeRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("invalid request: %v", err),
		})
		return
	}
	log.Info(ctx, "HealthCheck SlowQuery Analysis request", zap.Any("req", req))
	// 验证必填字段
	if req.TimeRange.Start.IsZero() || req.TimeRange.End.IsZero() {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "timeRange.start and timeRange.end are required",
		})
		return
	}

	if req.ClusterId == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "clusterId is required",
		})
		return
	}

	// 当 clusterUrls 或集群元信息未传时，通过 clusterId 反查。
	if shouldFetchHealthCheckClusterInfo(&req.HealthCheckCommonParameters, healthCheckClusterInfoNeeds{SlowQueryURL: true}) {
		clusterInfo, err := h.clinicClient.GetClusterDataURLs(ctx, req.ClusterId)
		if err != nil {
			log.Error(ctx, "failed to fetch cluster data urls",
				zap.String("cluster_id", req.ClusterId),
				zap.Error(err))
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("failed to fetch cluster info: %v", err),
			})
			return
		}
		fillHealthCheckClusterInfo(&req.HealthCheckCommonParameters, clusterInfo)
	}

	if req.ClusterUrls.SlowQueryS3URL == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "clusterUrls.slowQueryS3Url is required",
		})
		return
	}

	if req.Region == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "region is required",
		})
		return
	}

	// 获取阈值
	memThreshold := int64(service.HugeMemoryThreshold)
	if req.Params.MemMaxThreshold != nil {
		memThreshold = *req.Params.MemMaxThreshold
	}
	queryTimeThreshold := service.SlowQueryTimeThreshold
	if req.Params.QueryTimeThreshold != nil {
		queryTimeThreshold = *req.Params.QueryTimeThreshold
	}

	log.Info(ctx, "HealthCheck SlowQuery Analysis started",
		zap.String("clusterId", req.ClusterId),
		zap.String("timeRange", fmt.Sprintf("%s ~ %s", req.TimeRange.Start.Format(time.RFC3339), req.TimeRange.End.Format(time.RFC3339))),
		zap.Int64("memThreshold", memThreshold),
		zap.Int("queryTimeThreshold", queryTimeThreshold),
	)

	traceId := log.GeTraceId(ctx)
	newCtx, err := log.StartTraceWithTraceId(traceId, "MetricsDiff", "")
	if err != nil {
		c.JSON(http.StatusInternalServerError, myerr.NewInternalErr(err.Error()))
		return
	}
	go func() {

		// 执行分析
		result, err := h.analyzer.Analyze(newCtx, &req)
		if err != nil {
			log.Error(newCtx, "Analysis failed", zap.Error(err))
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("analysis failed: %v", err),
			})
			return
		}

		// 查询 digest detail（Top2 详情记录 + link）
		detailParams := &service.DigestDetailParams{
			OrgId:         req.TenantId,
			ProjectId:     req.ProjectId,
			ClusterID:     req.ClusterId,
			Provider:      req.Provider,
			Region:        req.Region,
			DeployType:    req.DeployType,
			ClinicBaseURL: h.config.ClinicBaseURL,
		}
		if err := h.analyzer.QueryDigestDetails(newCtx, &req, result.Patterns, detailParams); err != nil {
			log.Warn(newCtx, "Failed to query digest details, skipping", zap.Error(err))
		}

		// 转换为健康检查响应格式
		response := h.analyzer.ConvertToHealthCheckResponse(result, memThreshold, queryTimeThreshold)

		// 生成 S3 报告地址
		fileName := generateFileName(&req)
		s3Bucket := "delicated-healthcheck"
		s3Path := fmt.Sprintf("healthcheck-report/%s", fileName)
		response.ResultJsonUrl = fmt.Sprintf("s3://%s/%s", s3Bucket, s3Path)

		log.Info(newCtx, "HealthCheck SlowQuery Analysis completed",
			zap.Int("total_digests", len(response.Results)),
			zap.Int("total_records", response.Summary.TotalRecords),
		)

		if err := saveHealthCheckResultToS3(newCtx, &req, response); err != nil {
			log.Error(newCtx, "Failed to save result to S3", zap.Error(err))
		}

	}()

	c.JSON(http.StatusOK, nil)
}

// generateFileName 生成结果文件名
func generateFileName(req *service.AnalyzeRequest) string {
	if req.ReportId != "" && req.Name != "" {
		// 新格式：clusterId_reportId_name.json
		return fmt.Sprintf("%s_%s_%s.json", req.ClusterId, req.ReportId, req.Name)
	}
	// 旧格式（兼容）：slowquery_analysis_clusterId_startDate_endDate_timestamp.json
	startDate := req.TimeRange.Start.Format("2006-01-02")
	endDate := req.TimeRange.End.Format("2006-01-02")
	timestamp := time.Now().Format("20060102_150405")
	return fmt.Sprintf("slowquery_analysis_%s_%s_%s_%s.json", req.ClusterId, startDate, endDate, timestamp)
}

// saveHealthCheckResultToS3 保存健康检查结果到 S3
func saveHealthCheckResultToS3(ctx context.Context, req *service.AnalyzeRequest, response *service.HealthCheckAnalysisResponse) error {
	// 生成文件名
	fileName := generateFileName(req)

	// 本地保存
	filePath := fmt.Sprintf("./output/healthcheck-report/%s", fileName)
	if err := utils.WriteFile(filePath, response); err != nil {
		log.Error(ctx, "Failed to write file locally",
			zap.String("filePath", filePath),
			zap.Error(err),
		)
		return fmt.Errorf("write file failed: %w", err)
	}

	log.Info(ctx, "HealthCheck result saved locally", zap.String("filePath", filePath))

	// 如果是生产环境，上传到 S3
	if !config.IsLocal() {
		s3Path := fmt.Sprintf("healthcheck-report/%s", fileName)
		if err := aws.UploadFileToS3(filePath, s3Path); err != nil {
			log.Error(ctx, "Failed to upload to S3",
				zap.String("s3Path", s3Path),
				zap.Error(err),
			)
			return fmt.Errorf("upload to S3 failed: %w", err)
		}
		log.Info(ctx, "HealthCheck result uploaded to S3", zap.String("s3Path", s3Path))
	} else {
		log.Info(ctx, "Skip S3 upload (not in prod env)")
	}

	return nil
}

// RegisterRoutes 注册路由
func (h *SlowQueryHandler) RegisterRoutes(r *gin.Engine) {
	healthcheckGroup := r.Group("/clinic-internal/healthcheck")
	{
		healthcheckGroup.POST("/sql/slowquery-analyze", h.HealthCheckAnalyze)
	}
}

// MetricsHealthCheckHandler Metrics 巡检 HTTP 处理器
type MetricsHealthCheckHandler struct {
	metricsHCSvc *service.MetricsHealthCheckService
	config       *config.DataProxyConfig
	clinicClient *clinic_internal_api.Client
}

// NewMetricsHealthCheckHandler 创建 Metrics 巡检处理器
func NewMetricsHealthCheckHandler(svc *service.MetricsHealthCheckService, cfg *config.DataProxyConfig) *MetricsHealthCheckHandler {
	return &MetricsHealthCheckHandler{
		metricsHCSvc: svc,
		config:       cfg,
		clinicClient: clinic_internal_api.NewClient(cfg.ClinicAPIBase),
	}
}

// MetricsHealthCheckAnalyze Metrics 巡检接口
// POST /clinic-internal/healthcheck/metrics/analyze
func (h *MetricsHealthCheckHandler) MetricsHealthCheckAnalyze(c *gin.Context) {
	ctx := c.Request.Context()
	log.Info(ctx, "HealthCheck Metrics Analysis started",
		zap.String("env", config.AppConfig.Env))

	var req service.MetricsHealthCheckRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("invalid request: %v", err),
		})
		return
	}

	// 验证必填字段
	if req.ClusterId == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "clusterId is required",
		})
		return
	}

	if req.TimeRange.Start.IsZero() || req.TimeRange.End.IsZero() {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "timeRange.start and timeRange.end are required",
		})
		return
	}

	// 当 clusterUrls 或集群元信息未传时，通过 clusterId 反查。
	if shouldFetchHealthCheckClusterInfo(&req.HealthCheckCommonParameters, healthCheckClusterInfoNeeds{MetricsURL: true}) {
		clusterInfo, err := h.clinicClient.GetClusterDataURLs(ctx, req.ClusterId)
		if err != nil {
			log.Error(ctx, "failed to fetch cluster data urls",
				zap.String("cluster_id", req.ClusterId),
				zap.Error(err))
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("failed to fetch cluster info: %v", err),
			})
			return
		}
		fillHealthCheckClusterInfo(&req.HealthCheckCommonParameters, clusterInfo)
	}

	log.Info(ctx, "HealthCheck Metrics Analysis params",
		zap.String("clusterId", req.ClusterId),
		zap.String("deployType", req.DeployType),
		zap.String("physicalClusterId", req.PhysicalClusterId),
		zap.String("region", req.Region),
		zap.String("timeRange", fmt.Sprintf("%s ~ %s", req.TimeRange.Start.Format(time.RFC3339), req.TimeRange.End.Format(time.RFC3339))),
	)

	traceId := log.GeTraceId(ctx)
	newCtx, err := log.StartTraceWithTraceId(traceId, "MetricsDiff", "")
	if err != nil {
		c.JSON(http.StatusInternalServerError, myerr.NewInternalErr(err.Error()))
		return
	}
	// 异步执行巡检
	go func() {

		// 执行巡检
		response, err := h.metricsHCSvc.Analyze(newCtx, &req)
		if err != nil {
			log.Error(newCtx, "Metrics HealthCheck Analysis failed", zap.Error(err))
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("analysis failed: %v", err),
			})
			return
		}

		// 生成 S3 报告地址
		fileName := generateMetricsFileName(&req)
		s3Bucket := "delicated-healthcheck"
		s3Path := fmt.Sprintf("healthcheck-report/%s", fileName)
		response.ResultJsonUrl = fmt.Sprintf("s3://%s/%s", s3Bucket, s3Path)

		log.Info(newCtx, "HealthCheck Metrics Analysis completed",
			zap.Int("totalMetrics", response.Summary.TotalMetrics),
			zap.Int("needAttentionCount", response.Summary.NeedAttentionCount),
		)

		if err := saveMetricsHealthCheckResultToS3(newCtx, &req, response); err != nil {
			log.Error(newCtx, "Failed to save metrics healthcheck result to S3", zap.Error(err))
		}
	}()

	JSONNoEscape(c, http.StatusOK, nil)
}

func JSONNoEscape(c *gin.Context, status int, data interface{}) {
	c.Status(status)
	c.Header("Content-Type", "application/json")

	encoder := json.NewEncoder(c.Writer)
	encoder.SetEscapeHTML(false)
	_ = encoder.Encode(data)
}

// generateMetricsFileName 生成 Metrics 巡检结果文件名
func generateMetricsFileName(req *service.MetricsHealthCheckRequest) string {
	if req.ReportId != "" && req.Name != "" {
		return fmt.Sprintf("%s_%s_%s.json", req.ClusterId, req.ReportId, req.Name)
	}
	startDate := req.TimeRange.Start.Format("2006-01-02")
	endDate := req.TimeRange.End.Format("2006-01-02")
	timestamp := time.Now().Format("20060102_150405")
	return fmt.Sprintf("metrics_healthcheck_%s_%s_%s_%s.json", req.ClusterId, startDate, endDate, timestamp)
}

// saveMetricsHealthCheckResultToS3 保存 Metrics 巡检结果到 S3
func saveMetricsHealthCheckResultToS3(ctx context.Context, req *service.MetricsHealthCheckRequest, response *service.MetricsHealthCheckResponse) error {
	fileName := generateMetricsFileName(req)

	filePath := fmt.Sprintf("./output/healthcheck-report/%s", fileName)

	// ⭐ 修改点：使用你封装的 WriteJSONNoEscape
	if err := utils.WriteJSONNoEscape(filePath, response); err != nil {
		log.Error(ctx, "Failed to write file locally",
			zap.String("filePath", filePath),
			zap.Error(err),
		)
		return fmt.Errorf("write file failed: %w", err)
	}

	log.Info(ctx, "Metrics HealthCheck result saved locally", zap.String("filePath", filePath))

	if !config.IsLocal() {
		s3Path := fmt.Sprintf("healthcheck-report/%s", fileName)
		if err := aws.UploadFileToS3(filePath, s3Path); err != nil {
			log.Error(ctx, "Failed to upload to S3",
				zap.String("s3Path", s3Path),
				zap.Error(err),
			)
			return fmt.Errorf("upload to S3 failed: %w", err)
		}
		log.Info(ctx, "Metrics HealthCheck result uploaded to S3", zap.String("s3Path", s3Path))
	} else {
		log.Info(ctx, "Skip S3 upload (not in prod env)")
	}

	return nil
}

// RegisterRoutes 注册 Metrics 巡检路由
func (h *MetricsHealthCheckHandler) RegisterRoutes(r *gin.Engine) {
	healthcheckGroup := r.Group("/clinic-internal/healthcheck")
	{
		healthcheckGroup.POST("/metrics/analyze", h.MetricsHealthCheckAnalyze)
	}
}

// AIHealthCheckHandler AI 巡检分析 HTTP 处理器
type AIHealthCheckHandler struct {
	aiService *service.AIService
	config    *config.DataProxyConfig
}

// NewAIHealthCheckHandler 创建 AI 巡检分析处理器
func NewAIHealthCheckHandler(svc *service.AIService, cfg *config.DataProxyConfig) *AIHealthCheckHandler {
	return &AIHealthCheckHandler{
		aiService: svc,
		config:    cfg,
	}
}

// AIAnalyze AI 巡检分析接口
// POST /clinic-internal/healthcheck/ai/analyze
func (h *AIHealthCheckHandler) AIAnalyze(c *gin.Context) {
	ctx := c.Request.Context()
	log.Info(ctx, "AI HealthCheck Analysis started",
		zap.String("env", config.AppConfig.Env))

	var req service.AIAnalyzeRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("invalid request: %v", err),
		})
		return
	}

	log.Info(ctx, "AI HealthCheck Analysis params",
		zap.String("orgId", req.OrgID),
		zap.String("clusterId", req.ClusterID),
		zap.Strings("reportIds", req.ReportID),
		zap.String("model", req.Model),
	)

	start := time.Now()
	log.Info(ctx, "AI HealthCheck Analysis invoking service",
		zap.String("orgId", req.OrgID),
		zap.String("clusterId", req.ClusterID),
		zap.Int("reportCount", len(req.ReportID)),
		zap.String("model", req.Model),
	)
	resp, err := h.aiService.Analyze(ctx, &req)
	if err != nil {
		log.Error(ctx, "AI HealthCheck Analysis failed",
			zap.String("orgId", req.OrgID),
			zap.String("clusterId", req.ClusterID),
			zap.Int("reportCount", len(req.ReportID)),
			zap.String("model", req.Model),
			zap.Duration("latency", time.Since(start)),
			zap.Error(err),
		)
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("AI analysis failed: %v", err),
		})
		return
	}

	log.Info(ctx, "AI HealthCheck Analysis completed",
		zap.String("model", resp.Model),
		zap.Int("inputTokens", resp.InputTokens),
		zap.Int("outputTokens", resp.OutputTokens),
		zap.Duration("latency", time.Since(start)),
	)

	c.JSON(http.StatusOK, resp)
}

// RegisterRoutes 注册 AI 巡检分析路由
func (h *AIHealthCheckHandler) RegisterRoutes(r *gin.Engine) {
	healthcheckGroup := r.Group("/clinic-internal/healthcheck")
	{
		healthcheckGroup.POST("/ai/analyze", h.AIAnalyze)
	}
}
