package main

import (
	"time"

	"github.com/dgraph-io/badger/v4"
	lm "github.com/hrfee/jfa-go/logmessages"
	"github.com/hrfee/mediabrowser"
	"github.com/timshannon/badgerhold/v4"
)

// clearEmails removes stored emails for users which no longer exist.
// meant to be called with other such housekeeping functions, so assumes
// the user cache is fresh.
func (app *appContext) clearEmails() {
	app.debug.Println(lm.HousekeepingEmail)
	emails := app.storage.GetEmails()
	for _, email := range emails {
		_, err := app.jf.UserByID(email.JellyfinID, false)
		// Make sure the user doesn't exist, and no other error has occured
		switch err.(type) {
		case mediabrowser.ErrUserNotFound:
			app.storage.DeleteEmailsKey(email.JellyfinID)
		default:
			continue
		}
	}
}

// clearDiscord does the same as clearEmails, but for Discord Users.
func (app *appContext) clearDiscord() {
	app.debug.Println(lm.HousekeepingDiscord)
	discordUsers := app.storage.GetDiscord()
	for _, discordUser := range discordUsers {
		user, err := app.jf.UserByID(discordUser.JellyfinID, false)
		// Make sure the user doesn't exist, and no other error has occured
		switch err.(type) {
		case mediabrowser.ErrUserNotFound:
			// Remove role in case their account was deleted oustide of jfa-go
			app.discord.RemoveRole(discordUser.MethodID().(string))
			app.storage.DeleteDiscordKey(discordUser.JellyfinID)
		default:
			if user.Policy.IsDisabled {
				app.discord.RemoveRole(discordUser.MethodID().(string))
			}
			continue
		}
	}
}

// clearMatrix does the same as clearEmails, but for Matrix Users.
func (app *appContext) clearMatrix() {
	app.debug.Println(lm.HousekeepingMatrix)
	matrixUsers := app.storage.GetMatrix()
	for _, matrixUser := range matrixUsers {
		_, err := app.jf.UserByID(matrixUser.JellyfinID, false)
		// Make sure the user doesn't exist, and no other error has occured
		switch err.(type) {
		case mediabrowser.ErrUserNotFound:
			app.storage.DeleteMatrixKey(matrixUser.JellyfinID)
		default:
			continue
		}
	}
}

// clearTelegram does the same as clearEmails, but for Telegram Users.
func (app *appContext) clearTelegram() {
	app.debug.Println(lm.HousekeepingTelegram)
	telegramUsers := app.storage.GetTelegram()
	for _, telegramUser := range telegramUsers {
		_, err := app.jf.UserByID(telegramUser.JellyfinID, false)
		// Make sure the user doesn't exist, and no other error has occured
		switch err.(type) {
		case mediabrowser.ErrUserNotFound:
			app.storage.DeleteTelegramKey(telegramUser.JellyfinID)
		default:
			continue
		}
	}
}

func (app *appContext) clearPWRCaptchas() {
	app.debug.Println(lm.HousekeepingCaptcha)
	captchas := map[string]Captcha{}
	for k, capt := range app.pwrCaptchas {
		if capt.Generated.Add(CAPTCHA_VALIDITY * time.Second).After(time.Now()) {
			captchas[k] = capt
		}
	}
	app.pwrCaptchas = captchas
}

func (app *appContext) clearActivities() {
	app.debug.Println(lm.HousekeepingActivity)
	keepCount := app.config.Section("activity_log").Key("keep_n_records").MustInt(1000)
	maxAgeDays := app.config.Section("activity_log").Key("delete_after_days").MustInt(90)
	minAge := time.Now().AddDate(0, 0, -maxAgeDays)
	err := error(nil)
	errorSource := 0
	if maxAgeDays != 0 {
		err = app.storage.db.DeleteMatching(&Activity{}, badgerhold.Where("Time").Lt(minAge))
	}
	if err == nil && keepCount != 0 {
		// app.debug.Printf("Keeping %d records", keepCount)
		err = app.storage.db.DeleteMatching(&Activity{}, (&badgerhold.Query{}).Reverse().SortBy("Time").Skip(keepCount))
		if err != nil {
			errorSource = 1
		}
	}
	if err == badger.ErrTxnTooBig {
		app.debug.Printf(lm.ActivityLogTxnTooBig)
		list := []Activity{}
		if errorSource == 0 {
			app.storage.db.Find(&list, badgerhold.Where("Time").Lt(minAge))
		} else {
			app.storage.db.Find(&list, (&badgerhold.Query{}).Reverse().SortBy("Time").Skip(keepCount))
		}
		for _, record := range list {
			app.storage.DeleteActivityKey(record.ID)
		}
	}
}

func newHousekeepingDaemon(interval time.Duration, app *appContext) *GenericDaemon {
	d := NewGenericDaemon(interval, app,
		func(app *appContext) {
			app.debug.Println(lm.HousekeepingInvites)
			app.checkInvites()
		},
		func(app *appContext) { app.clearActivities() },
	)

	d.Name("Housekeeping")

	clearEmail := app.config.Section("email").Key("require_unique").MustBool(false)
	clearDiscord := discordEnabled && (app.config.Section("discord").Key("require_unique").MustBool(false) || app.config.Section("discord").Key("disable_enable_role").MustBool(false))
	clearTelegram := telegramEnabled && (app.config.Section("telegram").Key("require_unique").MustBool(false))
	clearMatrix := matrixEnabled && (app.config.Section("matrix").Key("require_unique").MustBool(false))
	clearPWR := app.config.Section("captcha").Key("enabled").MustBool(false) && !app.config.Section("captcha").Key("recaptcha").MustBool(false)

	if clearEmail || clearDiscord || clearTelegram || clearMatrix {
		d.appendJobs(func(app *appContext) { app.jf.CacheExpiry = time.Now() })
	}

	if clearEmail {
		d.appendJobs(func(app *appContext) { app.clearEmails() })
	}
	if clearDiscord {
		d.appendJobs(func(app *appContext) { app.clearDiscord() })
	}
	if clearTelegram {
		d.appendJobs(func(app *appContext) { app.clearTelegram() })
	}
	if clearMatrix {
		d.appendJobs(func(app *appContext) { app.clearMatrix() })
	}
	if clearPWR {
		d.appendJobs(func(app *appContext) { app.clearPWRCaptchas() })
	}

	return d
}