package handlers

import (
	"context"
	"errors"
	"fmt"
	"oral-friend/internal/initialization"
	"oral-friend/pkg/openai"

	"github.com/google/uuid"
	larkcard "github.com/larksuite/oapi-sdk-go/v3/card"
	larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)


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")      // å†…ç½®è§’è‰²é€‰æ‹©
	AIModeChooseKind   = CardKind("ai_mode_choose")   // AIæ¨¡å¼�é€‰æ‹©
)
type CardMsg struct {
	Kind      CardKind
	ChatType  CardChatType
	Value     interface{}
	SessionId string
	MsgId     string
}

type MenuOption struct {
	value string
	label string
}

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


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


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 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
}

// ç”Ÿæˆ�å¸¦æœ‰è§’è‰²æ ‡ç­¾ btn
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
}

// ä½¿ç”¨ AI æ¨¡å¼� Btn
func withAIModeBtn(sessionID *string, aiModeStrs []string) larkcard.MessageCardElement {
	var menuOptions []MenuOption
	for _, label := range aiModeStrs {
		menuOptions = append(menuOptions, MenuOption{
			label: label,
			value: label,
		})
	}

	cancelMenu := newMenu("é€‰æ‹©æ¨¡å¼�",
		map[string]interface{}{
			"value":     "0",
			"kind":      AIModeChooseKind,
			"sessionId": *sessionID,
			"msgId":     *sessionID,
		},
		menuOptions...,
	)

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

// 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
}


// 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
}

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())

		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 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
}

// 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 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)
}


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 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 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
}
// 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
}

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 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 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 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 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 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 SendAIModeListsCard(ctx context.Context,
	sessionId *string, msgId *string, aiModeStrs []string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ¤– AIæ¨¡å¼�é€‰æ‹©", larkcard.TemplateIndigo),
		withAIModeBtn(sessionId, aiModeStrs),
		withNote("æ��é†’ï¼šé€‰æ‹©å†…ç½®æ¨¡å¼�ï¼Œè®©AIæ›´å¥½çš„ç�†è§£æ‚¨çš„éœ€æ±‚ã€‚"))
	replyCard(ctx, msgId, newCard)
}

func sendNewTopicCard(ctx context.Context,
	sessionId *string, msgId *string, content string) {
	newCard, _ := newSendCard(
		withHeader("ğŸ‘»ï¸� å·²å¼€å�¯æ–°çš„è¯�é¢˜", larkcard.TemplateBlue),
		withMainText(content),
		withNote("æ��é†’ï¼šç‚¹å‡»å¯¹è¯�æ¡†å�‚ä¸�å›�å¤�ï¼Œå�¯ä¿�æŒ�è¯�é¢˜è¿�è´¯"))
	replyCard(ctx, msgId, newCard)
}