package im

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"
)

var preferredPostLocales = []string{"zh_cn", "en_us", "ja_jp"}

// DecodePlainText converts a supported received Lark message into plain text.
func DecodePlainText(messageType MessageType, content string) (string, error) {
	switch messageType {
	case MessageTypeText:
		var message RecvMessageText
		if err := json.Unmarshal([]byte(content), &message); err != nil {
			return "", fmt.Errorf("decode lark text message: %w", err)
		}
		return message.Text, nil
	case MessageTypePost:
		message, err := decodePost(content)
		if err != nil {
			return "", err
		}
		return postPlainText(message), nil
	default:
		return "", fmt.Errorf("unsupported lark message type %q", messageType)
	}
}

func decodePost(content string) (RecvMessagePost, error) {
	var fields map[string]json.RawMessage
	if err := json.Unmarshal([]byte(content), &fields); err != nil {
		return RecvMessagePost{}, fmt.Errorf("decode lark post message: %w", err)
	}
	_, hasTitle := fields["title"]
	_, hasContent := fields["content"]
	if hasTitle || hasContent {
		var message RecvMessagePost
		if err := json.Unmarshal([]byte(content), &message); err != nil {
			return RecvMessagePost{}, fmt.Errorf("decode lark post message: %w", err)
		}
		return message, nil
	}

	var localized map[string]RecvMessagePost
	if err := json.Unmarshal([]byte(content), &localized); err != nil {
		return RecvMessagePost{}, fmt.Errorf("decode localized lark post message: %w", err)
	}
	for _, locale := range preferredPostLocales {
		if message, ok := localized[locale]; ok {
			return message, nil
		}
	}
	locales := make([]string, 0, len(localized))
	for locale := range localized {
		locales = append(locales, locale)
	}
	sort.Strings(locales)
	if len(locales) == 0 {
		return RecvMessagePost{}, nil
	}
	return localized[locales[0]], nil
}

func postPlainText(message RecvMessagePost) string {
	lines := make([]string, 0, len(message.Content)+1)
	if message.Title != "" {
		lines = append(lines, message.Title)
	}
	for _, row := range message.Content {
		var line strings.Builder
		for _, item := range row {
			if (item.Tag == "text" || item.Tag == "a") && item.Text != nil {
				line.WriteString(*item.Text)
			}
		}
		if line.Len() > 0 {
			lines = append(lines, line.String())
		}
	}
	return strings.Join(lines, "\n")
}
