package main

import (
	"feishu-messager/pkg/feishu"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
)

type Message struct {
	MessageType string `json:"message_type"`
	Text        string `json:"text"`
	BotTag      string `json:"bot_tag"`
	ChatTag     string `json:"chat_tag"`
	Color       string `json:"color"`
	Title       string `json:"title"`
	ReceiverId  string `json:"receiver_id"`
	RawMode     bool   `json:"raw_mode"`
	IsUrgent    bool   `json:"is_urgent"`
	UrgentType  string `json:"urgent_type"`
}

type messageForwardResponse struct {
	statusCode      int
	responseJsonMap map[string]interface{}
}

var configMu sync.RWMutex

func main() {
	viper.Set("scope", "test")
	viper.SetDefault("server.listen_ip", "127.0.0.1")
	viper.SetDefault("server.listen_port", "80")
	viper.SetConfigName("conf.yaml") // name of config file (without extension)
	viper.SetConfigType("yaml")      // REQUIRED if the config file does not have the extension in the name
	viper.AddConfigPath("./config")  // optionally look for config in the working directory
	err := viper.ReadInConfig()      // Find and read the config file
	if err != nil {                  // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %w \n", err))
	}

	// Reload config every 5 min without stop the service
	go periodicallyConfigLoader()

	r := gin.Default()
	r.POST("/messageForward", messageForwardHandler)
	r.Run(viper.GetString("server.listen_ip") + ":" + viper.GetString("server.listen_port"))

}

func messageForwardHandler(c *gin.Context) {
	configMu.RLock()
	defer configMu.RUnlock()
	message := Message{Color: "orange", Title: "", BotTag: "default", ChatTag: "default", RawMode: false, IsUrgent: false, UrgentType: "in-app"}
	err := c.BindJSON(&message)
	if err != nil {
		log.Println(err)
		responseJson := map[string]interface{}{
			"status": "500 Internal Server Error",
			"text":   "Fail to parse JSON data.",
		}
		c.AsciiJSON(http.StatusInternalServerError, responseJson)
	} else {
		log.Println("Bot Tag:", message.BotTag)
		log.Println(viper.GetString("feishu_bot." + message.BotTag + ".app_secret"))
		feishuChatSetting := feishu.FeishuChatParams{AppId: viper.GetString("feishu_bot." + message.BotTag + ".app_id"), AppSecret: viper.GetString("feishu_bot." + message.BotTag + ".app_secret")}
		log.Println("FeishuSetting:", feishuChatSetting)
		if feishuChatSetting.AppId == "" || feishuChatSetting.AppSecret == "" {
			responseJson := map[string]interface{}{
				"status": "500 Internal Server Error",
				"text":   "Invalid tag or configuration.",
			}
			c.AsciiJSON(http.StatusInternalServerError, responseJson)
			return
		}
		if !message.IsUrgent {
			responseStruct := processNormalMessage(feishuChatSetting, message)
			c.AsciiJSON(responseStruct.statusCode, responseStruct.responseJsonMap)
		} else {
			responseStruct := processUrgentMessage(feishuChatSetting, message)
			c.AsciiJSON(responseStruct.statusCode, responseStruct.responseJsonMap)
		}
	}
}

func periodicallyConfigLoader() {
	for {
		configMu.Lock()
		err := viper.ReadInConfig()
		if err != nil {
			log.Println("Fail to load config")
		}
		configMu.Unlock()
		time.Sleep(5 * time.Minute)
	}
}

func processNormalMessage(feishuChatSetting feishu.FeishuChatParams, message Message) messageForwardResponse {
	if message.MessageType == "plaintext" {
		var err error
		var messageId string
		if message.RawMode {
			messageId, err = feishu.SendMessageToChat(feishuChatSetting, message.Text, message.ReceiverId)
		} else {
			receiver := viper.GetString("feishu_bot." + message.BotTag + ".feishu_chats." + message.ChatTag)
			if feishu.IsChatID(receiver) {
				messageId, err = feishu.SendMessageToChat(feishuChatSetting, message.Text, receiver)
			} else if _, errParse := url.Parse(receiver); errParse == nil {
				err = feishu.SendMessageToWebhook(message.Text, receiver)
				messageId = "webhook_messageId"
			}
		}
		if err == nil {
			responseJson := map[string]interface{}{
				"status":     "200 OK",
				"text":       "Succeed",
				"message_id": messageId,
			}
			return messageForwardResponse{statusCode: http.StatusOK, responseJsonMap: responseJson}
		} else {
			responseJson := map[string]interface{}{
				"status": "500 Internal Server Error",
				"text":   "Encounter a problem when sending the message, you can either ask the administrator to check the code or just retry.",
			}
			return messageForwardResponse{statusCode: http.StatusInternalServerError, responseJsonMap: responseJson}
		}
	} else if message.MessageType == "card" {
		var responseJson map[string]interface{}
		var err error
		var messageId string
		if message.RawMode {
			messageId, err = feishu.SendCardToChat(feishuChatSetting, feishu.FeishuCardParams{Title: message.Title, Color: message.Color, Text: message.Text}, message.ReceiverId)
		} else {
			receiver := viper.GetString("feishu_bot." + message.BotTag + ".feishu_chats." + message.ChatTag)
			if feishu.IsChatID(receiver) {
				messageId, err = feishu.SendCardToChat(feishuChatSetting, feishu.FeishuCardParams{Title: message.Title, Color: message.Color, Text: message.Text}, receiver)
			} else if _, errParse := url.Parse(receiver); errParse == nil {
				err = feishu.SendCardToWebhook(feishu.FeishuCardParams{Title: message.Title, Color: message.Color, Text: message.Text}, receiver)
				messageId = "webhook_messageId"
			}
		}
		if err != nil {
			log.Println(err)
			responseJson = map[string]interface{}{
				"status": "500 Internal Server Error",
				"text":   "Encounter a problem when sending the message, you can either ask the administrator to check the code or just retry.",
			}
			return messageForwardResponse{statusCode: http.StatusInternalServerError, responseJsonMap: responseJson}
		} else {
			responseJson = map[string]interface{}{
				"status":      "200 OK",
				"text":        "Succeed",
				"messsage_id": messageId,
			}
			return messageForwardResponse{statusCode: http.StatusOK, responseJsonMap: responseJson}
		}
	} else {
		responseJson := map[string]interface{}{
			"status": "501 Not Implemented",
			"text":   "This Message type " + message.MessageType + " is not supported yet, please follow our updates.",
		}
		return messageForwardResponse{statusCode: http.StatusNotImplemented, responseJsonMap: responseJson}
	}
}

func processUrgentMessage(feishuChatSetting feishu.FeishuChatParams, message Message) messageForwardResponse {
	// Current urgent message only supports raw mode
	if !message.RawMode {
		responseJson := map[string]interface{}{
			"status": "501 Not Implemented",
			"text":   "Urgent message only supports raw mode now.",
		}
		return messageForwardResponse{statusCode: http.StatusNotImplemented, responseJsonMap: responseJson}
	}
	if message.MessageType == "plaintext" {
		var err error
		messageId, err := feishu.SendUrgentMessageToChat(feishuChatSetting, message.Text, message.ReceiverId, message.UrgentType)
		if err == nil {
			responseJson := map[string]interface{}{
				"status":     "200 OK",
				"text":       "Succeed",
				"message_id": messageId,
			}
			return messageForwardResponse{statusCode: http.StatusOK, responseJsonMap: responseJson}
		} else {
			feishu.SendMessageToInternalReportChat(feishuChatSetting, fmt.Sprintf("send urgent message failed:%s, receiver_id: %s", err.Error(), message.ReceiverId))
			responseJson := map[string]interface{}{
				"status": "500 Internal Server Error",
				"text":   "Encounter a problem when sending the message, you can either ask the administrator to check the code or just retry.",
			}
			return messageForwardResponse{statusCode: http.StatusInternalServerError, responseJsonMap: responseJson}
		}
	} else if message.MessageType == "card" {
		var responseJson map[string]interface{}
		var err error
		messageId, err := feishu.SendUrgentCardToChat(feishuChatSetting, feishu.FeishuCardParams{Title: message.Title, Color: message.Color, Text: message.Text}, message.ReceiverId, message.UrgentType)
		if err != nil {
			feishu.SendMessageToInternalReportChat(feishuChatSetting, fmt.Sprintf("send urgent message failed: %s, receiver_id: %s", err.Error(), message.ReceiverId))
			responseJson = map[string]interface{}{
				"status": "500 Internal Server Error",
				"text":   "Encounter a problem when sending the message, you can either ask the administrator to check the code or just retry.",
			}
			return messageForwardResponse{statusCode: http.StatusInternalServerError, responseJsonMap: responseJson}
		} else {
			responseJson = map[string]interface{}{
				"status":     "200 OK",
				"text":       "Succeed",
				"message_id": messageId,
			}
			return messageForwardResponse{statusCode: http.StatusOK, responseJsonMap: responseJson}
		}
	} else {
		responseJson := map[string]interface{}{
			"status": "501 Not Implemented",
			"text":   "This Message type " + message.MessageType + " is not supported yet, please follow our updates.",
		}
		return messageForwardResponse{statusCode: http.StatusNotImplemented, responseJsonMap: responseJson}
	}
}
