package service

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/cockroachdb/errors"

	"github.com/pingcap/jira-bot/pkg/config"

	"github.com/pingcap/jira-bot/pkg/util"

	json "github.com/json-iterator/go"

	"github.com/larksuite/oapi-sdk-go/api"
	"github.com/larksuite/oapi-sdk-go/api/core/request"
	"github.com/larksuite/oapi-sdk-go/api/core/response"
	"github.com/larksuite/oapi-sdk-go/core"
	"github.com/larksuite/oapi-sdk-go/core/tools"

	"github.com/pingcap/jira-bot/model"
)

// cardTemplate generates a JSON boilerplate for card message
func cardTemplate(issue *model.Issue) (string, error) {
	toBeFormatted := "%v"
	url := fmt.Sprintf("http://%v/api/redirect?url=https://internal.pingcap.net/jira/browse/%s&msgid=%s",
		fmt.Sprintf("%s:%s", config.GetString("host"), config.GetString("port")), issue.ID, toBeFormatted)
	return fmt.Sprintf(`{
  "config": {
    "wide_screen_mode": false
  },
  "card_link": {
    "url": "%v"
  },
  "header": {
    "title": {
      "tag": "plain_text",
      "content": "Issue ID: 🔥%v🔥"
    },
    "template": "orange"
  },
  "i18n_elements": {
    "zh_cn": [
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": "%v"
        }
      },
      {
        "tag": "hr"
      },
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": "**Issue details**"
        }
      },
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": ""
        },
        "fields": [
          {
            "is_short": false,
            "text": {
              "tag": "lark_md",
              "content": "**Summary:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Status:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Priority:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Component:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Affect Version:**\n%v"
            }
          }
        ]
      },
      {
        "tag": "hr"
      },
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": "**People & Dates**"
        }
      },
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": ""
        },
        "fields": [
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Reporter:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Assignee:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Created:**\n%v"
            }
          },
          {
            "is_short": true,
            "text": {
              "tag": "lark_md",
              "content": "**Updated:**\n%v"
            }
          }
        ]
      }
    ]
  }
}`,
		url, issue.ID, toBeFormatted, issue.Summary,
		issue.Status, issue.Priority, issue.Component, issue.AffectVersion,
		issue.Reporter, issue.Assignee,
		issue.CreateTime.Format(model.TimeOutputLayout), issue.UpdateTime.Format(model.TimeOutputLayout)), nil
}

// NotifyIssue notifies users of issue creations
// but will not record issue to database
func NotifyIssue(ijob *IssueJob, notificationContent string) (*model.Message, error) {
	body := map[string]interface{}{
		"user_id":  ijob.User.FeishuUserId,
		"msg_type": "interactive",
	}

	message := model.Message{NotifyTag: model.NotifyTag, Receiver: ijob.User.Email}
	if ijob.NotificationTarget == model.NotificationTargetLeader {
		if ijob.User.FeishuLeaderUserId == "" {
			return nil, errors.New("feishuleaderuserid is empty")
		}

		body["user_id"] = ijob.User.FeishuLeaderUserId
		message.Receiver = ijob.User.LeaderEmail
	}

	err := model.Save(model.GetApp().DB, &message)
	if err != nil {
		return nil, err
	}

	if model.GetApp().AcFilter.IsInWhitelist(message.Receiver) && !ijob.Rule.InSilence(time.Now()) {
		template, err := cardTemplate(ijob.Issue)
		if err != nil {
			return nil, err
		}
		cardContent := fmt.Sprintf(template, message.ID, notificationContent)
		card := map[string]interface{}{}
		err = json.Unmarshal(util.StringToByteSlice(cardContent), &card)
		if err != nil {
			return nil, errors.Wrap(err, "json unmarshal failed")
		}
		body["card"] = card

		coreCtx := core.WrapContext(context.Background())
		ret := make(map[string]interface{})
		req := request.NewRequestWithNative("/open-apis/message/v4/send", "POST",
			request.AccessTokenTypeTenant, body, &ret,
		)
		err = api.Send(coreCtx, model.GetApp().LarkConf, req)
		if err != nil {
			log.Println(tools.Prettify(err))
			e := &response.Error{}
			if errors.As(err, e) {
				log.Println(e.Code)
				log.Println(e.Msg)
			}
			return nil, err
		}
		message.MessageId = ret["message_id"].(string)
	} else {
		if !model.GetApp().AcFilter.IsInWhitelist(message.Receiver) {
			message.NotifyTag = model.UnNotifyTagWL
		} else {
			message.NotifyTag = model.UnNotifyTagSli
		}
		log.Println("NotifyIssue unnotify ", message, time.Now(), ijob.Issue, ijob.Rule)
	}

	message.IssueId = ijob.Issue.ID
	message.Content = notificationContent
	return &message, nil
}
