package api

import (
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"

	"github.com/pingcap-inc/clinic/pkg/db"
	"github.com/pingcap-inc/clinic/pkg/db/model"
	error2 "github.com/pingcap-inc/clinic/pkg/error"
	"github.com/pingcap-inc/clinic/pkg/metrics"

	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"go.uber.org/zap"
)

// InitSystemAPI is used for health check without auth.
func InitSystemAPI(engin *gin.Engine) {
	router := engin.Group("/api/system")
	router.PUT("/associations/files/:uuid/jira-issues/:issue-id", func(context *gin.Context) {
		err := bindJiraIssueWithFile(context)
		if err != nil {
			SendErrorMessage(context, err)
		}
	})

	router.GET("/associations/files/:uuid/jira-issues", func(context *gin.Context) {
		resp, err := listJiraIssuesByFile(context)
		SendMessageWithReturn(context, err, resp)
	})

	router.GET("/associations/requests/file/jira-issues", func(context *gin.Context) {
		metrics.ListRecentJiraIssueBindRequestCount.WithLabelValues().Inc()
		resp, err := listRecentJiraIssueBindRequest(context)
		SendMessageWithReturn(context, err, resp)
	})
}

func listRecentJiraIssueBindRequest(context *gin.Context) (*BindRequestResponse, *error2.ClinicErr) {
	requests, err := model.ListRencentJiraAssociateRequest(time.Hour * 168)
	if err != nil {
		return nil, error2.InternalError(err)
	}
	return &BindRequestResponse{Requests: requests}, nil
}

func listJiraIssuesByFile(context *gin.Context) (*IssueListResponse, *error2.ClinicErr) {
	uuid := context.Param("uuid")
	issues, err := listJiraIssueByFileUUID(uuid)
	if err != nil {
		return nil, err
	}
	return &IssueListResponse{issues}, nil
}

func listJiraIssueByFileUUID(uuid string) ([]db.JiraIssue, *error2.ClinicErr) {
	file, err := model.QueryUploadFile(uuid)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			log.Warn("file not found", zap.Error(err))
			return nil, error2.RequestError(errors.New("file not found"))
		}
		return nil, error2.InternalError(err)
	}

	if file == nil {
		return nil, error2.NotFoundError(errors.New("file not found"))
	}

	assocs, err := model.ListAssociateBySink(db.AssociationEntityClinicFile, file.ID)
	if err != nil {
		log.Warn("error on list association", zap.Error(err))
		return nil, error2.InternalError(err)
	}
	ids := []uint{}
	for _, assoc := range assocs {
		if assoc.SourceNodeEntity == db.AssociationEntityJiraIssue {
			ids = append(ids, assoc.SourceNodeID)
		}
	}
	issues, err := model.ListJiraIssueByIds(ids)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			log.Warn("issue not found", zap.Error(err))
			return nil, error2.NotFoundError(errors.New("issue not found"))
		}
		return nil, error2.InternalError(err)
	}
	return issues, nil
}

func getLogSymptoms(context *gin.Context) (*LogSymptomsResponse, *error2.ClinicErr) {
	uuid := context.Param("uuid")

	syms, err := model.ListLogSym(uuid)
	if err != nil {
		return nil, error2.InternalError(err)
	}
	lsr := &LogSymptomsResponse{}
	for _, sym := range syms {
		lsr.Symptoms = append(lsr.Symptoms, LogSymptom{
			Name:   sym.Symptom,
			Kibana: sym.Kibana,
			KB:     strings.Split(sym.KB, ","),
			Jira:   strings.Split(sym.Jira, ","),
		})
	}
	return lsr, nil
}

//func oauthDownload(manager *manager.FileStoreageManager, context *gin.Context) *error2.ClinicErr {
//	//context.Params = append(context.Params, gin.Param{Key: "uuid", Value: context.Query("uuid")})
//	//fileUUID := context.Param("uuid")
//	return downloadFile(context.Query("uuid"), manager, context)
//}

func bindJiraIssueWithFile(context *gin.Context) *error2.ClinicErr {
	var issue db.JiraIssue
	if err := context.ShouldBindJSON(&issue); err != nil {
		log.Warn("unmarshal request body failed", zap.Error(err))
		return error2.RequestError(errors.New("unmarshal request failed"))
	}

	uuid := context.Param("uuid")
	if err := model.AssociateJiraIssueWithFile(uuid, &issue); err != nil {
		if err == gorm.ErrRecordNotFound {
			log.Warn("file not found", zap.Error(err))
			return error2.RequestError(errors.New("file not found"))
		}
		return error2.InternalError(err)
	}
	return nil
}
