// Package repository add by blacknc <blacknc@163.com> at 2023/06/16 14:56:45
package repository

import (
	"context"
	"dataservices/commons/errs"
	"dataservices/internal/entity"
	"time"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

func CreateEndpointExecRecord(ctx context.Context, record *entity.EndpointExecRecord) error {
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).Create(record).Error
	if err != nil {
		return errs.WrapGORMError(err, "failed to create execpoint execute record")
	}
	return nil
}

func DistinctEndpointExecRecord(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.EndpointExecRecord, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)
	var results []entity.EndpointExecRecord
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("distinct endpoint_id, dataapp_id, region").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Limit(limit).
		Scan(&results).Error

	if err != nil {
		return results, errs.WrapGORMError(err, "failed to DistinctEndpointExecRecord")
	}
	return results, nil
}

func GroupEndpointExecRecordByDataAppId(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisIntKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisIntKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("dataapp_id as `key`, COUNT(*) as value").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Group("dataapp_id").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountEndpointExecRecord")
	}
	if results != nil {
		tilog.Info(ctx, "GroupEndpointExecRecordByDataAppId", zap.Any("startTimeObj", startTimeObj),
			zap.Any("endTimeObj", endTimeObj), zap.Any("results", results))
	}
	return results, nil
}

func GroupEndpointExecRecordByEndpointId(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisIntKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisIntKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("endpoint_id as `key`, COUNT(*) as value").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Group("endpoint_id").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountEndpointExecRecord")
	}
	return results, nil
}

func CountEndpointExecRecordLatencyByEndpointId(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisIntKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisIntKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("endpoint_id as `key`, CAST(AVG(end_ms-start_ms) AS signed) as value").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Group("endpoint_id").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountEndpointExecRecord")
	}
	if results != nil {
		tilog.Info(ctx, "GroupEndpointExecRecordByDataAppId", zap.Any("startTimeObj", startTimeObj),
			zap.Any("endTimeObj", endTimeObj), zap.Any("results", results))
	}
	return results, nil
}

func GroupEndpointExecRecordByRegion(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisStrKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisStrKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("region as `key`, COUNT(*) as value").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Group("region").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountEndpointExecRecord")
	}
	if results != nil {
		tilog.Info(ctx, "GroupEndpointExecRecordByDataAppId", zap.Any("startTimeObj", startTimeObj),
			zap.Any("endTimeObj", endTimeObj), zap.Any("results", results))
	}
	return results, nil
}

func GroupEndpointExecRecordByApiKey(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisStrIntKKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisStrIntKKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("caller as `key1`, dataapp_id as key2, COUNT(*) as value").
		Where("created_at between ? and ?", startTimeObj, endTimeObj).
		Group("caller, dataapp_id").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountEndpointExecRecord")
	}
	if results != nil {
		tilog.Info(ctx, "GroupEndpointExecRecordByApiKey", zap.Any("startTimeObj", startTimeObj),
			zap.Any("endTimeObj", endTimeObj), zap.Any("results", results))
	}
	return results, nil
}

func CountTestEndpointUsers(ctx context.Context, startSecAt int64, endSecAt int64, limit int) ([]entity.AnalysisStrKVResult, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)

	var results []entity.AnalysisStrKVResult
	err := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).
		Select("caller as `key`, COUNT(1) as value").
		Where("created_at between ? and ? and channel='inner_test'", startTimeObj, endTimeObj).
		Group("caller").
		Limit(limit).
		Scan(&results).Error
	if err != nil {
		return results, errs.WrapGORMError(err, "failed to CountTestEndpointUsers")
	}
	if results != nil {
		tilog.Info(ctx, "CountTestEndpointUsers", zap.Any("startTimeObj", startTimeObj),
			zap.Any("endTimeObj", endTimeObj), zap.Any("results", results))
	}
	return results, nil
}

func ListTestEndpointsByTimeRange(ctx context.Context, startSecAt int64, endSecAt int64) ([]*entity.EndpointExecRecord, error) {
	startTimeObj := time.Unix(startSecAt, 0)
	endTimeObj := time.Unix(endSecAt, 0)
	var res []*entity.EndpointExecRecord
	txDB := MustFromContext(ctx).Table(entity.TableEndpointExecRecord).Where("created_at between ? and ? and channel='inner_test'", startTimeObj, endTimeObj)
	if err := txDB.Find(&res).Error; err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list dataapp")
	}
	return res, nil
}
