package handlers

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/google/uuid"
	larkcard "github.com/larksuite/oapi-sdk-go/v3/card"
	larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
	"start-feishubot/initialization"
	"start-feishubot/services"
	"start-feishubot/services/openai"
)

type CardKind string
type CardChatType string

var (
	ClearCardKind      = CardKind("clear")            // æ¸…ç©ºä¸Šä¸‹æ–‡
	PicModeChangeKind  = CardKind("pic_mode_change")  // åˆ‡æ�¢å›¾ç‰‡åˆ›ä½œæ¨¡å¼�
	PicResolutionKind  = CardKind("pic_resolution")   // å›¾ç‰‡åˆ†è¾¨ç�‡è°ƒæ•´
	PicTextMoreKind    = CardKind("pic_text_more")    // é‡�æ–°æ ¹æ�®æ–‡æœ¬ç”Ÿæˆ�å›¾ç‰‡
	PicVarMoreKind     = CardKind("pic_var_more")     // å�˜é‡�å›¾ç‰‡
	RoleTagsChooseKind = CardKind("role_tags_choose") // å†…ç½®è§’è‰²æ‰€å±�æ ‡ç­¾é€‰æ‹©
	RoleChooseKind     = CardKind("role_choose")      // å†…ç½®è§’è‰²é€‰æ‹©
)

var (
	GroupChatType = CardChatType("group")
	UserChatType  = CardChatType("personal")
)

type CardMsg struct {
	Kind      CardKind
	ChatType  CardChatType
	Value     interface{}
	SessionId string
	MsgId     string
}

type MenuOption struct {
	value string
	label string
}

func replyCard(ctx context.Context,
	msgId *string,
	cardContent string,
) error {
	client := initialization.GetLarkClient()
	resp, err := client.Im.Message.Reply(ctx, larkim.NewReplyMessageReqBuilder().
		MessageId(*msgId).
		Body(larkim.NewReplyMessageReqBodyBuilder().
			MsgType(larkim.MsgTypeInteractive).
			Uuid(uuid.New().String()).
			Content(cardContent).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return errors.New(resp.Msg)
	}
	return nil
}

func replyCardWithBackId(ctx context.Context,
	msgId *string,
	cardContent string,
) (*string, error) {
	client := initialization.GetLarkClient()
	resp, err := client.Im.Message.Reply(ctx, larkim.NewReplyMessageReqBuilder().
		MessageId(*msgId).
		Body(larkim.NewReplyMessageReqBodyBuilder().
			MsgType(larkim.MsgTypeInteractive).
			Uuid(uuid.New().String()).
			Content(cardContent).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return nil, errors.New(resp.Msg)
	}

	//ctx = context.WithValue(ctx, "SendMsgId", *resp.Data.MessageId)
	//SendMsgId := ctx.Value("SendMsgId")
	//pp.Println(SendMsgId)
	return resp.Data.MessageId, nil
}

func newSendCard(header *larkcard.MessageCardHeader, elements ...larkcard.MessageCardElement) (string, error) {
	config := larkcard.NewMessageCardConfig().
		WideScreenMode(false).
		EnableForward(true).
		UpdateMulti(true).
		Build()
	var aElementPool []larkcard.MessageCardElement
	for _, element := range elements {
		aElementPool = append(aElementPool, element)
	}
	// å�¡ç‰‡æ¶ˆæ�¯ä½“
	cardContent, err := larkcard.NewMessageCard().
		Config(config).
		Header(header).
		Elements(
			aElementPool,
		).
		String()
	return cardContent, err
}
func newSendCardWithOutHeader(
	elements ...larkcard.MessageCardElement) (string, error) {
	config := larkcard.NewMessageCardConfig().
		WideScreenMode(false).
		EnableForward(true).
		UpdateMulti(true).
		Build()
	var aElementPool []larkcard.MessageCardElement
	for _, element := range elements {
		aElementPool = append(aElementPool, element)
	}
	// å�¡ç‰‡æ¶ˆæ�¯ä½“
	cardContent, err := larkcard.NewMessageCard().
		Config(config).
		Elements(
			aElementPool,
		).
		String()
	return cardContent, err
}

func newSimpleSendCard(
	elements ...larkcard.MessageCardElement) (string,
	error) {
	config := larkcard.NewMessageCardConfig().
		WideScreenMode(false).
		EnableForward(true).
		UpdateMulti(false).
		Build()
	var aElementPool []larkcard.MessageCardElement
	for _, element := range elements {
		aElementPool = append(aElementPool, element)
	}
	// å�¡ç‰‡æ¶ˆæ�¯ä½“
	cardContent, err := larkcard.NewMessageCard().
		Config(config).
		Elements(
			aElementPool,
		).
		String()
	return cardContent, err
}

// withSplitLine ç”¨äº�ç”Ÿæˆ�åˆ†å‰²çº¿
func withSplitLine() larkcard.MessageCardElement {
	splitLine := larkcard.NewMessageCardHr().
		Build()
	return splitLine
}

// withHeader ç”¨äº�ç”Ÿæˆ�æ¶ˆæ�¯å¤´
func withHeader(title string, color string) *larkcard.
	MessageCardHeader {
	if title == "" {
		title = "ğŸ¤–ï¸�æœºå™¨äººæ��é†’"
	}
	header := larkcard.NewMessageCardHeader().
		Template(color).
		Title(larkcard.NewMessageCardPlainText().
			Content(title).
			Build()).
		Build()
	return header
}

// withNote ç”¨äº�ç”Ÿæˆ�çº¯æ–‡æœ¬è„šæ³¨
func withNote(note string) larkcard.MessageCardElement {
	noteElement := larkcard.NewMessageCardNote().
		Elements([]larkcard.MessageCardNoteElement{larkcard.NewMessageCardPlainText().
			Content(note).
			Build()}).
		Build()
	return noteElement
}

// withMainMd ç”¨äº�ç”Ÿæˆ�markdownæ¶ˆæ�¯ä½“
func withMainMd(msg string) larkcard.MessageCardElement {
	msg, i := processMessage(msg)
	msg = processNewLine(msg)
	if i != nil {
		return nil
	}
	mainElement := larkcard.NewMessageCardDiv().
		Fields([]*larkcard.MessageCardField{larkcard.NewMessageCardField().
			Text(larkcard.NewMessageCardLarkMd().
				Content(msg).
				Build()).
			IsShort(true).
			Build()}).
		Build()
	return mainElement
}

// withMainText ç”¨äº�ç”Ÿæˆ�çº¯æ–‡æœ¬æ¶ˆæ�¯ä½“
func withMainText(msg string) larkcard.MessageCardElement {
	msg, i := processMessage(msg)
	msg = cleanTextBlock(msg)
	if i != nil {
		return nil
	}
	mainElement := larkcard.NewMessageCardDiv().
		Fields([]*larkcard.MessageCardField{larkcard.NewMessageCardField().
			Text(larkcard.NewMessageCardPlainText().
				Content(msg).
				Build()).
			IsShort(false).
			Build()}).
		Build()
	return mainElement
}

func withImageDiv(imageKey string) larkcard.MessageCardElement {
	imageElement := larkcard.NewMessageCardImage().
		ImgKey(imageKey).
		Alt(larkcard.NewMessageCardPlainText().Content("").
			Build()).
		Preview(true).
		Mode(larkcard.MessageCardImageModelCropCenter).
		CompactWidth(true).
		Build()
	return imageElement
}

// withMdAndExtraBtn ç”¨äº�ç”Ÿæˆ�å¸¦æœ‰é¢�å¤–æŒ‰é’®çš„æ¶ˆæ�¯ä½“
func withMdAndExtraBtn(msg string, btn *larkcard.
	MessageCardEmbedButton) larkcard.MessageCardElement {
	msg, i := processMessage(msg)
	msg = processNewLine(msg)
	if i != nil {
		return nil
	}
	mainElement := larkcard.NewMessageCardDiv().
		Fields(
			[]*larkcard.MessageCardField{
				larkcard.NewMessageCardField().
					Text(larkcard.NewMessageCardLarkMd().
						Content(msg).
						Build()).
					IsShort(true).
					Build()}).
		Extra(btn).
		Build()
	return mainElement
}

func newBtn(content string, value map[string]interface{},
	typename larkcard.MessageCardButtonType) *larkcard.
	MessageCardEmbedButton {
	btn := larkcard.NewMessageCardEmbedButton().
		Type(typename).
		Value(value).
		Text(larkcard.NewMessageCardPlainText().
			Content(content).
			Build())
	return btn
}

func newMenu(
	placeHolder string,
	value map[string]interface{},
	options ...MenuOption,
) *larkcard.
	MessageCardEmbedSelectMenuStatic {
	var aOptionPool []*larkcard.MessageCardEmbedSelectOption
	for _, option := range options {
		aOption := larkcard.NewMessageCardEmbedSelectOption().
			Value(option.value).
			Text(larkcard.NewMessageCardPlainText().
				Content(option.label).
				Build())
		aOptionPool = append(aOptionPool, aOption)

	}
	btn := larkcard.NewMessageCardEmbedSelectMenuStatic().
		MessageCardEmbedSelectMenuStatic(larkcard.NewMessageCardEmbedSelectMenuBase().
			Options(aOptionPool).
			Placeholder(larkcard.NewMessageCardPlainText().
				Content(placeHolder).
				Build()).
			Value(value).
			Build()).
		Build()
	return btn
}

// æ¸…é™¤å�¡ç‰‡æŒ‰é’®
func withClearDoubleCheckBtn(sessionID *string) larkcard.MessageCardElement {
	confirmBtn := newBtn("ç¡®è®¤æ¸…é™¤", map[string]interface{}{
		"value":     "1",
		"kind":      ClearCardKind,
		"chatType":  UserChatType,
		"sessionId": *sessionID,
	}, larkcard.MessageCardButtonTypeDanger,
	)
	cancelBtn := newBtn("æˆ‘å†�æƒ³æƒ³", map[string]interface{}{
		"value":     "0",
		"kind":      ClearCardKind,
		"sessionId": *sessionID,
		"chatType":  UserChatType,
	},
		larkcard.MessageCardButtonTypeDefault)

	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{confirmBtn, cancelBtn}).
		Layout(larkcard.MessageCardActionLayoutBisected.Ptr()).
		Build()

	return actions
}

func withPicModeDoubleCheckBtn(sessionID *string) larkcard.
	MessageCardElement {
	confirmBtn := newBtn("åˆ‡æ�¢æ¨¡å¼�", map[string]interface{}{
		"value":     "1",
		"kind":      PicModeChangeKind,
		"chatType":  UserChatType,
		"sessionId": *sessionID,
	}, larkcard.MessageCardButtonTypeDanger,
	)
	cancelBtn := newBtn("æˆ‘å†�æƒ³æƒ³", map[string]interface{}{
		"value":     "0",
		"kind":      PicModeChangeKind,
		"sessionId": *sessionID,
		"chatType":  UserChatType,
	},
		larkcard.MessageCardButtonTypeDefault)

	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{confirmBtn, cancelBtn}).
		Layout(larkcard.MessageCardActionLayoutBisected.Ptr()).
		Build()

	return actions
}

func withOneBtn(btn *larkcard.MessageCardEmbedButton) larkcard.
	MessageCardElement {
	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{btn}).
		Layout(larkcard.MessageCardActionLayoutFlow.Ptr()).
		Build()
	return actions
}

//æ–°å»ºå¯¹è¯�æŒ‰é’®

func withPicResolutionBtn(sessionID *string) larkcard.
	MessageCardElement {
	cancelMenu := newMenu("é»˜è®¤åˆ†è¾¨ç�‡",
		map[string]interface{}{
			"value":     "0",
			"kind":      PicResolutionKind,
			"sessionId": *sessionID,
			"msgId":     *sessionID,
		},
		MenuOption{
			label: "256x256",
			value: string(services.Resolution256),
		},
		MenuOption{
			label: "512x512",
			value: string(services.Resolution512),
		},
		MenuOption{
			label: "1024x1024",
			value: string(services.Resolution1024),
		},
	)

	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{cancelMenu}).
		Layout(larkcard.MessageCardActionLayoutFlow.Ptr()).
		Build()
	return actions
}
func withRoleTagsBtn(sessionID *string, tags ...string) larkcard.
	MessageCardElement {
	var menuOptions []MenuOption

	for _, tag := range tags {
		menuOptions = append(menuOptions, MenuOption{
			label: tag,
			value: tag,
		})
	}
	cancelMenu := newMenu("é€‰æ‹©è§’è‰²åˆ†ç±»",
		map[string]interface{}{
			"value":     "0",
			"kind":      RoleTagsChooseKind,
			"sessionId": *sessionID,
			"msgId":     *sessionID,
		},
		menuOptions...,
	)

	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{cancelMenu}).
		Layout(larkcard.MessageCardActionLayoutFlow.Ptr()).
		Build()
	return actions
}

func withRoleBtn(sessionID *string, titles ...string) larkcard.
	MessageCardElement {
	var menuOptions []MenuOption

	for _, tag := range titles {
		menuOptions = append(menuOptions, MenuOption{
			label: tag,
			value: tag,
		})
	}
	cancelMenu := newMenu("æŸ¥çœ‹å†…ç½®è§’è‰²",
		map[string]interface{}{
			"value":     "0",
			"kind":      RoleChooseKind,
			"sessionId": *sessionID,
			"msgId":     *sessionID,
		},
		menuOptions...,
	)

	actions := larkcard.NewMessageCardAction().
		Actions([]larkcard.MessageCardActionElement{cancelMenu}).
		Layout(larkcard.MessageCardActionLayoutFlow.Ptr()).
		Build()
	return actions
}

func replyMsg(ctx context.Context, msg string, msgId *string) error {
	msg, i := processMessage(msg)
	if i != nil {
		return i
	}
	client := initialization.GetLarkClient()
	content := larkim.NewTextMsgBuilder().
		Text(msg).
		Build()

	resp, err := client.Im.Message.Reply(ctx, larkim.NewReplyMessageReqBuilder().
		MessageId(*msgId).
		Body(larkim.NewReplyMessageReqBodyBuilder().
			MsgType(larkim.MsgTypeText).
			Uuid(uuid.New().String()).
			Content(content).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return errors.New(resp.Msg)
	}
	return nil
}

func uploadImage(base64Str string) (*string, error) {
	imageBytes, err := base64.StdEncoding.DecodeString(base64Str)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	client := initialization.GetLarkClient()
	resp, err := client.Im.Image.Create(context.Background(),
		larkim.NewCreateImageReqBuilder().
			Body(larkim.NewCreateImageReqBodyBuilder().
				ImageType(larkim.ImageTypeMessage).
				Image(bytes.NewReader(imageBytes)).
				Build()).
			Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return nil, errors.New(resp.Msg)
	}
	return resp.Data.ImageKey, nil
}
func replyImage(ctx context.Context, ImageKey *string,
	msgId *string) error {
	//fmt.Println("sendMsg", ImageKey, msgId)

	msgImage := larkim.MessageImage{ImageKey: *ImageKey}
	content, err := msgImage.String()
	if err != nil {
		fmt.Println(err)
		return err
	}
	client := initialization.GetLarkClient()

	resp, err := client.Im.Message.Reply(ctx, larkim.NewReplyMessageReqBuilder().
		MessageId(*msgId).
		Body(larkim.NewReplyMessageReqBodyBuilder().
			MsgType(larkim.MsgTypeImage).
			Uuid(uuid.New().String()).
			Content(content).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return errors.New(resp.Msg)
	}
	return nil

}

func replayImageCardByBase64(ctx context.Context, base64Str string,
	msgId *string, sessionId *string, question string) error {
	imageKey, err := uploadImage(base64Str)
	if err != nil {
		return err
	}
	//example := "img_v2_041b28e3-5680-48c2-9af2-497ace79333g"
	//imageKey := &example
	//fmt.Println("imageKey", *imageKey)
	err = sendImageCard(ctx, *imageKey, msgId, sessionId, question)
	if err != nil {
		return err
	}
	return nil
}

func sendMsg(ctx context.Context, msg string, chatId *string) error {
	//fmt.Println("sendMsg", msg, chatId)
	msg, i := processMessage(msg)
	if i != nil {
		return i
	}
	client := initialization.GetLarkClient()
	content := larkim.NewTextMsgBuilder().
		Text(msg).
		Build()

	//fmt.Println("content", content)

	resp, err := client.Im.Message.Create(ctx, larkim.NewCreateMessageReqBuilder().
		ReceiveIdType(larkim.ReceiveIdTypeChatId).
		Body(larkim.NewCreateMessageReqBodyBuilder().
			MsgType(larkim.MsgTypeText).
			ReceiveId(*chatId).
			Content(content).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return errors.New(resp.Msg)
	}
	return nil
}

func PatchCard(ctx context.Context, msgId *string,
	cardContent string) error {
	//fmt.Println("sendMsg", msg, chatId)
	client := initialization.GetLarkClient()
	//content := larkim.NewTextMsgBuilder().
	//	Text(msg).
	//	Build()

	//fmt.Println("content", content)

	resp, err := client.Im.Message.Patch(ctx, larkim.NewPatchMessageReqBuilder().
		MessageId(*msgId).
		Body(larkim.NewPatchMessageReqBodyBuilder().
			Content(cardContent).
			Build()).
		Build())

	// å¤„ç�†é”™è¯¯
	if err != nil {
		fmt.Println(err)
		return err
	}

	// æœ�åŠ¡ç«¯é”™è¯¯å¤„ç�†
	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return errors.New(resp.Msg)
	}
	return nil
}

func sendClearCacheCheckCard(ctx context.Context,
	sessionId *string, msgId *string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ†‘ æœºå™¨äººæ��é†’", larkcard.TemplateBlue),
		withMainMd("æ‚¨ç¡®å®šè¦�æ¸…é™¤å¯¹è¯�ä¸Šä¸‹æ–‡å�—ï¼Ÿ"),
		withNote("è¯·æ³¨æ„�ï¼Œè¿™å°†å¼€å§‹ä¸€ä¸ªå…¨æ–°çš„å¯¹è¯�ï¼Œæ‚¨å°†æ— æ³•åˆ©ç”¨ä¹‹å‰�è¯�é¢˜çš„å�†å�²ä¿¡æ�¯"),
		withClearDoubleCheckBtn(sessionId))
	replyCard(ctx, msgId, newCard)
}

func sendSystemInstructionCard(ctx context.Context,
	sessionId *string, msgId *string, content string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ¥·  å·²è¿›å…¥è§’è‰²æ‰®æ¼”æ¨¡å¼�", larkcard.TemplateIndigo),
		withMainText(content),
		withNote("è¯·æ³¨æ„�ï¼Œè¿™å°†å¼€å§‹ä¸€ä¸ªå…¨æ–°çš„å¯¹è¯�ï¼Œæ‚¨å°†æ— æ³•åˆ©ç”¨ä¹‹å‰�è¯�é¢˜çš„å�†å�²ä¿¡æ�¯"))
	replyCard(ctx, msgId, newCard)
}

func sendOnProcessCard(ctx context.Context,
	sessionId *string, msgId *string) (*string, error) {
	newCard, _ := newSendCardWithOutHeader(
		withNote("æ­£åœ¨æ€�è€ƒï¼Œè¯·ç¨�ç­‰..."))
	id, err := replyCardWithBackId(ctx, msgId, newCard)
	if err != nil {
		return nil, err
	}
	return id, nil
}

func updateTextCard(ctx context.Context, msg string,
	msgId *string) error {
	newCard, _ := newSendCardWithOutHeader(
		withMainText(msg),
		withNote("æ­£åœ¨ç”Ÿæˆ�ï¼Œè¯·ç¨�ç­‰..."))
	err := PatchCard(ctx, msgId, newCard)
	if err != nil {
		return err
	}
	return nil
}
func updateFinalCard(ctx context.Context, msg string,
	msgId *string) error {
	newCard, _ := newSendCardWithOutHeader(
		withMainText(msg))
	err := PatchCard(ctx, msgId, newCard)
	if err != nil {
		return err
	}
	return nil
}

func sendHelpCard(ctx context.Context,
	sessionId *string, msgId *string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ�’éœ€è¦�å¸®åŠ©å�—ï¼Ÿ", larkcard.TemplateBlue),
		withMainMd("**æˆ‘æ˜¯å…·å¤‡æ‰“å­—æœºæ•ˆæ�œçš„è�Šå¤©æœºå™¨äººï¼�**"),
		withSplitLine(),
		withMdAndExtraBtn(
			"** ğŸ†‘ æ¸…é™¤è¯�é¢˜ä¸Šä¸‹æ–‡**\næ–‡æœ¬å›�å¤� *æ¸…é™¤* æˆ– */clear*",
			newBtn("ç«‹åˆ»æ¸…é™¤", map[string]interface{}{
				"value":     "1",
				"kind":      ClearCardKind,
				"chatType":  UserChatType,
				"sessionId": *sessionId,
			}, larkcard.MessageCardButtonTypeDanger)),
		withMainMd("ğŸ›– **å†…ç½®è§’è‰²åˆ—è¡¨** \n"+" æ–‡æœ¬å›�å¤� *è§’è‰²åˆ—è¡¨* æˆ– */roles*"),
		withMainMd("ğŸ¥· **è§’è‰²æ‰®æ¼”æ¨¡å¼�**\næ–‡æœ¬å›�å¤�*è§’è‰²æ‰®æ¼”* æˆ– */system*+ç©ºæ ¼+è§’è‰²ä¿¡æ�¯"),
		withSplitLine(),
		withMainMd("ğŸ�’ **éœ€è¦�æ›´å¤šå¸®åŠ©**\næ–‡æœ¬å›�å¤� *å¸®åŠ©* æˆ– */help*"),
	)
	replyCard(ctx, msgId, newCard)
}

func sendImageCard(ctx context.Context, imageKey string,
	msgId *string, sessionId *string, question string) error {
	newCard, _ := newSimpleSendCard(
		withImageDiv(imageKey),
		withSplitLine(),
		//å†�æ�¥ä¸€å¼ 
		withOneBtn(newBtn("å†�æ�¥ä¸€å¼ ", map[string]interface{}{
			"value":     question,
			"kind":      PicTextMoreKind,
			"chatType":  UserChatType,
			"msgId":     *msgId,
			"sessionId": *sessionId,
		}, larkcard.MessageCardButtonTypePrimary)),
	)
	replyCard(ctx, msgId, newCard)
	return nil
}

func sendBalanceCard(ctx context.Context, msgId *string,
	balance openai.BalanceResponse) {
	newCard, _ := newSendCard(
		withHeader("ğŸ�°ï¸� ä½™é¢�æŸ¥è¯¢", larkcard.TemplateBlue),
		withMainMd(fmt.Sprintf("æ€»é¢�åº¦: %.2f$", balance.TotalGranted)),
		withMainMd(fmt.Sprintf("å·²ç”¨é¢�åº¦: %.2f$", balance.TotalUsed)),
		withMainMd(fmt.Sprintf("å�¯ç”¨é¢�åº¦: %.2f$",
			balance.TotalAvailable)),
		withNote(fmt.Sprintf("æœ‰æ•ˆæœŸ: %s - %s",
			balance.EffectiveAt.Format("2006-01-02 15:04:05"),
			balance.ExpiresAt.Format("2006-01-02 15:04:05"))),
	)
	replyCard(ctx, msgId, newCard)
}

func SendRoleTagsCard(ctx context.Context,
	sessionId *string, msgId *string, roleTags []string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ›– è¯·é€‰æ‹©è§’è‰²ç±»åˆ«", larkcard.TemplateIndigo),
		withRoleTagsBtn(sessionId, roleTags...),
		withNote("æ��é†’ï¼šé€‰æ‹©è§’è‰²æ‰€å±�åˆ†ç±»ï¼Œä»¥ä¾¿æˆ‘ä»¬ä¸ºæ‚¨æ�¨è��æ›´å¤šç›¸å…³è§’è‰²ã€‚"))
	replyCard(ctx, msgId, newCard)
}

func SendRoleListCard(ctx context.Context,
	sessionId *string, msgId *string, roleTag string, roleList []string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ›– è§’è‰²åˆ—è¡¨"+" - "+roleTag, larkcard.TemplateIndigo),
		withRoleBtn(sessionId, roleList...),
		withNote("æ��é†’ï¼šé€‰æ‹©å†…ç½®åœºæ™¯ï¼Œå¿«é€Ÿè¿›å…¥è§’è‰²æ‰®æ¼”æ¨¡å¼�ã€‚"))
	replyCard(ctx, msgId, newCard)
}
