package main

import (
	"context"
	"encoding/json"
	"log"
	"os"
	"sync"

	"github.com/Authing/authing-go-sdk/lib/management"
	"github.com/larksuite/oapi-sdk-go/core"
	v1 "github.com/larksuite/oapi-sdk-go/service/im/v1"
	"gorm.io/gorm"

	"github.com/pingcap/crm-bot/crm"
	"github.com/pingcap/crm-bot/pkg/config"
	"github.com/pingcap/crm-bot/pkg/db"
	"github.com/pingcap/crm-bot/pkg/job"
	"github.com/pingcap/crm-bot/pkg/lark"
	"github.com/pingcap/crm-bot/pkg/util"
)

type App struct {
	DB          *gorm.DB
	Lark        *lark.Lark
	Users       map[string]*CRM_User
	Lock        sync.RWMutex
	AccessToken string
}

func (app *App) OnStartup() {
	loadCRMRemindConf(loadLarkSheet(app.Lark, config.GetString("sheettoken"), "A:E"))

	users := []CRM_User{}
	err := Find(app.DB, &users)
	if err != nil {
		log.Println("[error] OnStartup err ", err)
		return
	}

	for idx, _ := range users {
		user := users[idx]
		user.AppInst = app
		todos := []CRM_Todo{}
		app.DB.Find(&todos, &CRM_Todo{Owner: user.Email})
		user.Todos = make(map[string]*CRM_Todo)
		for i := range todos {
			todo := &todos[i]
			todo.user = &user
			json.Unmarshal(util.StringToByteSlice(todo.NotificationContent), &todo.Tags)
			user.Todos[todo.Id] = todo
			todo.DealRemainder()
		}
		app.Users[user.Email] = &user

		job.AddJob("@every 5m", app.Users[user.Email])
	}

	// update accessToken
	job.AddJob("@every 4m", job.JobRunner(func() {
		app.Lock.Lock()
		app.AccessToken = crm.GetAccessToken()
		app.Lock.Unlock()
	}))

	// query new active users
	job.AddJob("@every 30m", job.JobRunner(func() {
		userPoolId := "6114dd1f753f9920f1ca06cf"
		appSecret := os.Getenv("crmAppSecret")
		client := management.NewClient(userPoolId, appSecret)
		resp, err := client.ListApplicationActiveUsers("61527e0124a5f0df0eed7af2", 1, 500)
		if err != nil {
			log.Println("[error] ListApplicationActiveUsers ", err)
			return
		}

		crmUsers := []CRM_User{}
		app.Lock.RLock()
		accessToken := app.AccessToken
		app.Lock.RUnlock()
		for _, activeUser := range resp.List {
			if _, ok := app.Users[activeUser.Email]; ok {
				continue
			}

			crmUserId := crm.GetOpenUserID(activeUser.Phone, accessToken)
			if crmUserId == "" {
				continue
			}

			larkOpenId := app.Lark.GetOpenIdByEmail(activeUser.Email)
			if larkOpenId == "" {
				continue
			}
			crmUsers = append(crmUsers, CRM_User{Email: activeUser.Email,
				LarkOpenId: larkOpenId, CRMUserId: crmUserId,
				Name:  activeUser.Name,
				Todos: make(map[string]*CRM_Todo),
			})
		}

		log.Println("Add New Watching User By Post Request", crmUsers)

		app.Lock.Lock()
		for idx, _ := range crmUsers {
			crmUser := crmUsers[idx]
			crmUser.AppInst = app
			app.Users[crmUser.Email] = &crmUser

			job.AddJob("@every 5m", app.Users[crmUser.Email])
		}
		app.Lock.Unlock()

		_ = Save(app.DB, crmUsers)
	}))
}

func NewApp() (*App, error) {
	var err error
	app := App{}
	app.DB, err = db.InitDb(config.GetString("db"))
	if err != nil {
		return nil, err
	}

	app.Users = make(map[string]*CRM_User)
	app.Lark = lark.NewLark()
	app.AccessToken = crm.GetAccessToken()
	return &app, err
}

func (app *App) sendCard(todo *CRM_Todo, user *CRM_User, fn func(*CardTemplate)) error {
	log.Println("sendCard", todo)
	coreCtx := core.WrapContext(context.Background())
	reqBody := v1.MessageCreateReqBody{}
	reqBody.ReceiveId = user.LarkOpenId
	reqBody.MsgType = "interactive"
	reqBody.Content = cardTemplate(todo, fn)

	messageReq := app.Lark.LarkMessageService.Messages.Create(coreCtx, &reqBody)
	messageReq.SetReceiveIdType("open_id")

	resp, err := messageReq.Do()
	if err != nil {
		return err
	}
	log.Println(resp)

	return nil
}
