package model

import (
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

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

const (
	NotificationTargetSpecialLeader = "special"
	NotificationTargetLeader        = "leader"
	NotificationTargetAssignee      = "assignee"
	NotificationTargetReporter      = "reporter"
	NotificationTargetWatcher       = "watcher"
)

var rulePath string

func SetRulePath(path string) {
	rulePath = path
}

type Message struct {
	ID        int64  `gorm:"primaryKey"`
	MessageId string `gorm:"type:varchar(255)"` // messageId from lark server
	IssueId   string `gorm:"type:varchar(255)"`
	Content   string `gorm:"type:text"`
	NotifyTag string `gorm:"-"`
	Receiver  string `gorm:"type:varchar(255)"`
}

type NotificationRules struct {
	Lock  sync.RWMutex       `json:"-"`
	Rules []NotificationRule `json:"rules"`
}

type NotificationRule struct {
	Priority    string `json:"priority"`
	TriggerGap  int    `json:"trigger_gap"`
	Target      string `json:"target"`
	Frequency   int    `json:"frequency"`
	Content     string `json:"content"`
	SilenceTime string `json:"silence_time"`
	SilenceDay  string `json:"silence_day"`
	Status      string `json:"status"`
}

func (rule NotificationRule) IsNil() bool {
	return rule.Priority == "" && rule.Target == ""
}

func (rule *NotificationRule) InSilence(now time.Time) bool {
	zeroTime := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
	dailySeconds := int(now.Sub(zeroTime).Seconds())

	silenceArr := strings.Split(rule.SilenceTime, "-")
	if len(silenceArr) != 2 {
		log.Println("rule silenceTime config err, ", rule)
		return false
	}
	beginSec, err := strconv.Atoi(strings.TrimSpace(silenceArr[0]))
	if err != nil {
		log.Println("rule silenceTime config err, ", rule)
		return false
	}
	endSec, err := strconv.Atoi(strings.TrimSpace(silenceArr[1]))
	if err != nil {
		log.Println("rule silenceTime config err, ", rule)
		return false
	}

	slienceDayArr := strings.Split(rule.SilenceDay, ",")
	if len(slienceDayArr) != 0 {
		for _, dayStr := range slienceDayArr {
			day, _ := strconv.Atoi(dayStr)
			if now.Weekday() == time.Weekday(day) {
				return true
			}
		}
	}

	if beginSec < endSec {
		return dailySeconds >= beginSec && dailySeconds <= endSec
	} else {
		return dailySeconds >= beginSec || dailySeconds <= endSec
	}
}

func (rules *NotificationRules) GetRule(index int) NotificationRule {
	rules.Lock.RLock()
	defer rules.Lock.RUnlock()
	if index > len(rules.Rules) {
		return NotificationRule{}
	}

	return rules.Rules[index-1]
}

func (rules *NotificationRules) LoadFromFile() error {
	rules.Lock.Lock()
	defer rules.Lock.Unlock()
	rulesBytes, err := os.ReadFile(rulePath)
	if err != nil {
		return err
	}

	err = json.Unmarshal(rulesBytes, rules)
	if err != nil {
		return err
	}

	log.Println("Load rule file success!")
	return nil
}
