package main

import (
	"context"
	"flag"

	"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/log"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/query"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/s3"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/thirdapi/feishu"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/utils"
	"go.uber.org/zap"
)

var (
	day  = flag.String("day", "", "Specify date")
	task = flag.String("task", "slowquery", "specify task to run: slowquery or topsql")
)

// init function will be executed before main function, suitable for log configuration and other initialization operations
func Init() {

	// 1. Load configuration and set global configuration
	err := config.LoadConfig()
	if err != nil {
		// t.Fatalf("Failed to load config: %v", err)
		log.PlainError("Failed to load config", zap.Error(err))
	}
	log.PlainInfo("load config successful, env: " + config.AppConfig.Env)

	// 2. Initialize log configuration
	if err := log.InitLog(config.AppConfig.LogDir); err != nil {
		log.PlainError("Failed to initialize log", zap.Error(err))
	}

	flag.Parse() // Parse command line arguments
	if *day == "" {
		log.PlainInfo("day is empty")
	} else {
		config.AppConfig.Day = *day
		log.PlainInfo("user args day: " + *day)
	}
	log.PlainInfo("load config successful, day: " + config.AppConfig.Day)

}

// startLocalSlowQueryCheck Process local S3 slow query log files and send Feishu report
func startLocalSlowQueryCheck(ctx context.Context) {

	orgClusters, err := common.ListOrgClusters(ctx)
	if err != nil {
		log.Error(ctx, "ListOrgClusters failed", zap.Error(err))
		return
	}
	for orgId, _ := range orgClusters {
		log.Info(ctx, "start to parese org file: "+orgId)
		org := config.GetOrgByID(orgId)
		// 1. Parse local S3 log files into database and get statistics
		s3Stats, err := s3.ProcessLocalS3Logs(ctx, orgId)
		if err != nil {
			log.Error(ctx, "Failed to process local S3 logs", zap.Error(err))
			return
		}
		if s3Stats.SlowQueryCount == 0 {
			log.Info(ctx, "No slow query log found, skip")
			continue
		}

		// 2. Query and analyze from database, and send Feishu report
		querySqlLite, err := query.NewQuerySqlLite(ctx, *org)
		if err != nil {
			log.Error(ctx, "Failed to create querySqlLite ", zap.Error(err))
			return
		}
		defer querySqlLite.Close()

		finalOutput, err := querySqlLite.RunS3SlowQueryAnalysis(ctx, s3Stats)
		if err != nil {
			log.Error(ctx, "Failed RunS3SlowQueryAnalysis", zap.String("org", org.OrgID), zap.Error(err))

			panic("Failed to RunS3SlowQueryAnalysis")

		}
		finalOutput.DocLink = org.DocumentUrl

		// 3. Write Feishu document
		feishu.NewReportWriter(*org).WriteResult(*finalOutput)

		// 4. Send Feishu card message
		feishu.SendMessageCard(*finalOutput, org.ReceiveID...)

		if config.IsDev() {
			return
		}
		// 5. Clean files
		utils.CleanFiles(orgId)
	}

}

func startS3Download(ctx context.Context) {
	log.Info(ctx, "Starting to download files from S3...")

	if err := s3.DownloadS3FilesFromConfig(ctx); err != nil {
		log.Error(ctx, "Failed to download files from S3", zap.Error(err))
		panic("Failed to download files from S3")
	}

	log.Info(ctx, "File download completed successfully")
}

// // startS3Upload Upload files to specified S3 directory
// func startS3Upload(files []string, targetPrefix string) {
// 	log.PlainInfo("Starting to upload files to S3...")

// 	if err := s3.UploadFilesFromConfig(files, targetPrefix); err != nil {
// 		log.PlainError("Failed to upload files to S3", zap.Error(err))
// 		panic("Failed to upload files to S3")
// 	}

// 	log.PlainInfo("File upload completed successfully")
// }

/*
func main() {
	lambda.Start(clusterDiffHandler)
}

type Response events.APIGatewayProxyResponse

func clusterDiffHandler(ctx context.Context, request events.LambdaFunctionURLRequest) (events.LambdaFunctionURLResponse, error) {
	Init()
	var req dto.QueryComparisonRequest
	if err := json.Unmarshal([]byte(request.Body), &req); err != nil {
		return events.LambdaFunctionURLResponse{
			StatusCode: 400,
			Body:       fmt.Sprintf("invalid request: %v", err),
		}, nil
	}
	clusterAID := req.ClusterA.ClusterID
	clusterBID := req.ClusterB.ClusterID
	aliasA := req.ClusterA.Alias
	aliasB := req.ClusterB.Alias
	aStart, err := dto.ParseTimeFlexible(req.ClusterA.TimeRange.Start)
	if err != nil {
		return events.LambdaFunctionURLResponse{StatusCode: 400, Body: fmt.Sprintf("invalid request: %v", err)}, nil
	}
	aEnd, err := dto.ParseTimeFlexible(req.ClusterA.TimeRange.End)
	if err != nil || !aEnd.After(aStart) {
		return events.LambdaFunctionURLResponse{StatusCode: 400, Body: fmt.Sprintf("invalid request: %v", err)}, nil
	}
	bStart, err := dto.ParseTimeFlexible(req.ClusterB.TimeRange.Start)
	if err != nil {
		return events.LambdaFunctionURLResponse{StatusCode: 400, Body: fmt.Sprintf("invalid request: %v", err)}, nil
	}
	bEnd, err := dto.ParseTimeFlexible(req.ClusterB.TimeRange.End)
	if err != nil || !bEnd.After(bStart) {
		return events.LambdaFunctionURLResponse{StatusCode: 400, Body: fmt.Sprintf("invalid request: %v", err)}, nil
	}

	if clusterAID == "" || clusterBID == "" {
		return events.LambdaFunctionURLResponse{StatusCode: 400, Body: fmt.Sprintf("invalid request: %v", "cluster_id required")}, nil
	}
	ca := config.GetClusterByID(clusterAID)
	cb := config.GetClusterByID(clusterBID)
	if ca == nil {
		return events.LambdaFunctionURLResponse{StatusCode: 404, Body: fmt.Sprintf("invalid request: %v", "baseline cluster not found")}, nil
	}
	if cb == nil {
		return events.LambdaFunctionURLResponse{StatusCode: 404, Body: fmt.Sprintf("invalid request: %v", "canary cluster not found")}, nil
	}

	topN := req.Options.TopN
	if topN <= 0 {
		topN = service.DefaultTopN()
	}
	svc := service.NewClusterDiffApiService(nil, nil)
	diffParam := service.ClusterDiffParam{
		ClusterA:       service.ClusterInfo{ClusterId: clusterAID, Alias: aliasA, TimeRange: dto.TimeRange{Start: aStart, End: aEnd}},
		ClusterB:       service.ClusterInfo{ClusterId: clusterBID, Alias: aliasB, TimeRange: dto.TimeRange{Start: bStart, End: bEnd}},
		TopN:           topN,
		DigestDiffKeys: req.Options.DigestDiffKeys,
		DigestSources:  req.Options.DigestSources,
	}
	response, err := svc.BuildComparisonResponse(ctx, diffParam)
	if err != nil {
		return events.LambdaFunctionURLResponse{StatusCode: 500, Body: fmt.Sprintf("internal server error: %v", err)}, nil
	}
	fileName := fmt.Sprintf("./output/diff.json")
	log.Info(ctx, "QueryComparison success", zap.Any("fileName", fileName))

	utils.WriteFile(fileName, response)

	respBody, _ := json.Marshal(map[string]string{
		"message": "success",
	})
	return events.LambdaFunctionURLResponse{
		StatusCode: 200,
		Body:       string(respBody),
	}, nil
}
*/
