package feishu

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/config"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/dto"
	log2 "github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"

	larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
	"go.uber.org/zap"
)

func SendMessageWithStr(msgStr string, receiveID ...string) {
	// Format as JSON format
	msgJson := fmt.Sprintf(`{"text":"%s"}`, msgStr)
	// Send Feishu message
	SendMessageWithJson(msgJson, receiveID...)
}

// SendMessageWithJson Send message to specified receive ID
func SendMessageWithJson(msgJson string, receiveID ...string) {
	receiveIDs := GetEffectiveReceiveID(receiveID...)
	// Create Client
	client := newLarkClient()

	// Create request object
	for _, id := range receiveIDs {
		req := larkim.NewCreateMessageReqBuilder().
			ReceiveIdType(`chat_id`).
			Body(larkim.NewCreateMessageReqBodyBuilder().
				ReceiveId(id).
				MsgType(`text`).
				Content(msgJson).
				Build()).
			Build()

		resp, err := client.Im.V1.Message.Create(context.Background(), req)
		if err != nil {
			log2.PlainError("Failed to create Feishu message", zap.Error(err))
			continue
		}
		if !resp.Success() {
			log2.PlainError("Feishu API error", zap.String("logId", resp.RequestId()), zap.String("error", larkcore.Prettify(resp.CodeError)))
			continue
		}
		log2.PlainInfo("Feishu message sent successfully to " + id + ": " + larkcore.Prettify(resp))
	}
}

// SendMessageCard Send card message to specified receive ID
func SendMessageCard(f dto.FinalOutput, receiveID ...string) {
	// Use GetEffectiveReceiveID to get effective receive ID
	receiveIDs := GetEffectiveReceiveID(receiveID...)
	if config.IsDev() {
		f.DocLink = config.AppConfig.Feishu.DocumentUrl
	}
	totalNewDigest := 0
	// Assemble carTemplateContent
	var tableRawArray []TableRow
	// Sort keys in CriticalDetails according to order value in configuration
	sortedKeys := config.SortedPatternNames(f.Summary.CriticalDetails)
	for _, patternName := range sortedKeys {
		// No longer use values in CriticalDetails as Total
		newDigest := f.Summary.NewDigests[patternName]
		totalNewDigest += newDigest
		// Find QueryResult corresponding to patternName and get CountGE10 value
		countGE10 := 0
		for _, queryResult := range f.QueryResults {
			if queryResult.QueryName == patternName {
				countGE10 = queryResult.TotalCount.CountGE10
				break
			}
		}
		tableRawArray = append(tableRawArray, TableRow{
			PatternName: patternName,
			Total:       strconv.Itoa(countGE10),
			NewDigest:   strconv.Itoa(newDigest),
		})
	}
	log2.PlainInfo("", zap.String("tableRawArray", larkcore.Prettify(tableRawArray)))

	dayDate, err := time.Parse("20060102", f.Summary.Day)
	if err != nil {
		log2.PlainError("Failed to parse date %s: %v", zap.String("date", f.Summary.Day), zap.Error(err))
		return
	}
	reportDate := dayDate.Format("2006/01/02")
	var titleColor string
	var riskText string
	if totalNewDigest > 0 {
		titleColor = "orange"
		riskText = "Risks:" + strconv.Itoa(totalNewDigest)
	} else {
		titleColor = "blue"
		riskText = "NoRisk"
	}

	t := CardTemplateContent{
		Type: "template",
		Data: TemplateData{
			TemplateID:          config.AppConfig.Feishu.CardTemplate.TemplateID,
			TemplateVersionName: config.AppConfig.Feishu.CardTemplate.TemplateVersionName,
			TemplateVariable: TemplateVariable{
				OrgName:    f.Summary.OrgName,
				Day:        reportDate,
				TitleColor: titleColor,
				RiskText:   riskText,
				DocLink: Link{
					PcUrl:      f.DocLink,
					AndroidUrl: f.DocLink,
					IosUrl:     f.DocLink,
					Url:        f.DocLink,
				},
				TableRawArray: tableRawArray,
			},
		},
	}
	for _, id := range receiveIDs {
		sendMessageCardToReceiveID(t, id)
	}
}

// sendMessageCardToReceiveID Send card message to specified receive ID
func sendMessageCardToReceiveID(t CardTemplateContent, receiveID string) {

	byteStr, err := json.Marshal(t)
	if err != nil {
		log2.PlainError("Failed to marshal Feishu message", zap.Error(err))
		return
	}
	msgJson := string(byteStr)
	log2.PlainInfo("msgJson", zap.String("msgJson", msgJson))

	// Create Client
	client := newLarkClient()

	// Create request object
	req := larkim.NewCreateMessageReqBuilder().
		ReceiveIdType(`chat_id`).
		Body(larkim.NewCreateMessageReqBodyBuilder().
			ReceiveId(receiveID).
			MsgType(`interactive`).
			Content(msgJson).
			Build()).
		Build()
	log2.PlainInfo("req", zap.String("req", larkcore.Prettify(req)))
	// Send request
	resp, err := client.Im.V1.Message.Create(context.Background(), req)

	// Handle error
	if err != nil {
		log2.PlainError("Failed to create Feishu message", zap.Error(err))
		return
	}

	// Server error handling
	if !resp.Success() {
		log2.PlainError("Feishu API error", zap.String("logId", resp.RequestId()), zap.String("error", larkcore.Prettify(resp.CodeError)))
		return
	}

	// Business processing
	log2.PlainInfo("Feishu message sent successfully to " + receiveID + ": " + larkcore.Prettify(resp))
}

// GetEffectiveReceiveID Get effective receive ID
func GetEffectiveReceiveID(receiveID ...string) []string {
	var receiveIDs []string
	if config.IsDev() || len(receiveID) == 0 {
		receiveIDs = strings.Split(config.AppConfig.Feishu.ReceiveID, ",")
		log2.PlainInfo("using default receiveIDs: " + strings.Join(receiveIDs, ", "))
	} else {
		receiveIDs = receiveID
	}
	return receiveIDs
}

// GetEffectiveDocumentID Get effective document ID
func GetEffectiveDocumentID(documentID ...string) string {
	documentIDStr := ""
	if config.IsDev() || len(documentID) == 0 {
		documentIDStr = config.AppConfig.Feishu.DocumentID
		log2.PlainInfo("using default documentID: " + documentIDStr)
	} else if len(documentID) > 0 && documentID[0] != "" {
		documentIDStr = documentID[0]
	} else {
		documentIDStr = config.AppConfig.Feishu.DocumentID
	}
	return documentIDStr
}
