package plugins

import (
	"fmt"
	"kurumibot/database"
	"kurumibot/database/psql"
	"kurumibot/utils"
	"math"
	"math/rand/v2"
	"strconv"
	"strings"
	"time"

	"kurumibot/laniakea"

	"github.com/shopspring/decimal"
)

func RegisterEconomy(bot *laniakea.Bot) {
	economy := laniakea.NewPlugin("Economy")
	economy = economy.Command(profile, "profile", "профиль")
	economy = economy.Command(work, "work", "работать")
	economy = economy.Command(collect, "collect", "собрать")
	economy = economy.Command(code, "code", "код")

	economy = economy.Command(vacancies, "vacancies", "вакансии")
	economy = economy.Command(getAJob, "getajob", "устроиться")

	economy = economy.Command(aboutGroup, "group", "о группе")

	economy = economy.Command(about, "about", "о боте")

	go passiveIncome(bot)

	bot.AddPlugins(economy.Build())
}

func about(msgCtx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	out := []string{
		fmt.Sprintf("Go: %s", "1.25.0"),
		fmt.Sprintf("Версия laniakea: %s", laniakea.VersionString),
	}
	msgCtx.Answer(strings.Join(out, "\n"))
}

func passiveIncome(b *laniakea.Bot) {
	for {
		users, err := psql.GetAllUsers()
		if err != nil {
			b.Logger().Error(err)
			continue
		}

		for _, user := range users {
			if user.Business == nil && user.Maid == nil && user.Miner == nil {
				continue
			}

			if time.Now().Before(user.IncomeTime.Add(time.Hour * 3)) {
				continue
			}

			moneyIncome := decimal.NewFromInt(0)
			expIncome := decimal.NewFromInt(0)
			btcIncome := decimal.NewFromInt(0)

			if user.Business != nil {
				moneyIncome = moneyIncome.Add(user.Business.Income).Mul(user.Group.Multiplier)
			}
			if user.Maid != nil {
				expIncome = expIncome.Add(user.Maid.Income).Mul(user.Group.Multiplier)
			}
			if user.Miner != nil {
				btcIncome = btcIncome.Add(user.Miner.Income).Mul(user.Group.Multiplier)
			}

			waifus, err := psql.GetUserWaifus(user.ID)
			if err != nil {
				b.Logger().Error(err)
				continue
			}
			for _, waifu := range waifus {
				moneyIncome = moneyIncome.Mul(waifu.MoneyBonus)
				expIncome = expIncome.Mul(waifu.ExpBonus)
				btcIncome = btcIncome.Mul(waifu.MoneyBonus)
			}

			expIncome = expIncome.Mul(decimal.NewFromFloat(0.25))
			moneyIncome = moneyIncome.Mul(decimal.NewFromFloat(0.25))
			btcIncome = btcIncome.Mul(decimal.NewFromFloat(0.25))

			user.ExpIncome += int(expIncome.IntPart())
			user.MoneyIncome = user.MoneyIncome.Add(moneyIncome)
			user.BtcIncome = user.BtcIncome.Add(btcIncome)
			user.IncomeTime = time.Now().Add(-time.Hour * 2)
			database.PostgresDatabase.Save(user)

			b.Logger().Debug(fmt.Sprintf("У %d было пассивно собрано. След. сбор через час\n", user.TelegramID))
		}

		time.Sleep(time.Second * 5)
	}
}

func profile(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	user, err := psql.GetOrCreateUser(ctx.FromID, ctx.Update.Message.From.FirstName)
	if err != nil {
		ctx.Answer(err.Error())
		return
	}

	pair := "нет"
	if user.Pair != nil {
		pair = user.Pair.Name
	}

	fraction := "нет"
	if user.Fraction != nil {
		fraction = user.Fraction.Name
	}

	auto := "нет"
	if user.Auto != nil {
		auto = fmt.Sprintf("%s (ID: %d)", user.Auto.Name, user.Auto.ID)
	}
	business := "нет"
	if user.Business != nil {
		business = fmt.Sprintf("%s (ID: %d)", user.Business.Name, user.Business.ID)
	}
	maid := "нет"
	if user.Maid != nil {
		maid = fmt.Sprintf("%s (ID: %d)", user.Maid.Name, user.Maid.ID)
	}
	miner := "нет"
	if user.Miner != nil {
		miner = fmt.Sprintf("%s (ID: %d)", user.Miner.Name, user.Miner.ID)
	}
	_, needXp := psql.CountLevel(user.Exp)

	out := []string{
		fmt.Sprintf("🖤%s, %s🖤", user.Greeting, user.Name),
		fmt.Sprintf("🆔ID: %d", user.ID),
		fmt.Sprintf("🔰Фракция: %s", fraction),
		fmt.Sprintf("📊Группа: %s (ID: %d, x%.1f)", user.Group.Name, user.Group.ID, user.Group.Multiplier.InexactFloat64()),
		fmt.Sprintf("❤️Пара: %s", pair),
		fmt.Sprintf("💡Уровень: %d (%d опыта, %d опыта до повышения)", user.Level, user.Exp, needXp-user.Exp),
		fmt.Sprintf("💴Баланс: %s¥ %s, %s₿", utils.DecimalComma(&user.Balance), utils.Short(user.Balance.String()), utils.DecimalComma(&user.BTC)),
		fmt.Sprintf("💼Работа: %s (ID: %d)", user.Work.Name, user.Work.ID),
		fmt.Sprintf("🚘Авто: %s", auto),
		fmt.Sprintf("🏢Бизнес: %s", business),
		fmt.Sprintf("👩‍🦳Горничная: %s", maid),
		fmt.Sprintf("🖥Майнер: %s", miner),
	}
	ctx.Answer(strings.Join(out, "\n"))
}

func work(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	user, err := psql.GetOrCreateUser(ctx.FromID, ctx.Update.Message.From.FirstName)
	if err != nil {
		ctx.Error(err)
		return
	}

	if time.Now().Before(user.WorkTime.Add(time.Minute * 10)) {
		nextTime := time.Since(user.WorkTime.Add(time.Minute * 10))
		seconds := int(math.Round(math.Abs(nextTime.Seconds())))
		minutes := seconds / 60
		seconds -= minutes * 60
		ctx.Answer(fmt.Sprintf("Приходи через %02d:%02d", minutes, seconds))
		return
	}
	work := user.Work
	exp := rand.IntN(work.MaxExp-work.MinExp) + work.MinExp
	// Count exp
	expToAdd := decimal.NewFromInt(int64(exp)).Mul(user.Group.Multiplier)
	// Count money
	moneyToAdd := work.MoneyIncome.Mul(user.Group.Multiplier)

	waifus, err := psql.GetUserWaifus(user.ID)
	if err != nil {
		ctx.Error(err)
		return
	}
	for _, waifu := range waifus {
		expToAdd = expToAdd.Mul(waifu.ExpBonus)
		moneyToAdd = moneyToAdd.Mul(waifu.MoneyBonus)
	}
	user.Exp += int(expToAdd.IntPart())
	user.Balance = user.Balance.Add(moneyToAdd)
	user.WorkTime = time.Now()
	user.Level, _ = psql.CountLevel(user.Exp)
	database.PostgresDatabase.Save(user)
	ctx.Answer(fmt.Sprintf(
		"Ты заработал %s¥ и %d опыта.\nПриходи через 10 минут.",
		utils.DecimalComma(&work.MoneyIncome),
		expToAdd.IntPart(),
	))
}

func collect(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	user, err := psql.GetOrCreateUser(ctx.FromID, ctx.Update.Message.From.FirstName)
	if err != nil {
		ctx.Error(err)
		return
	}

	if user.Business == nil && user.Maid == nil && user.Miner == nil {
		ctx.Answer("Нечего собирать!")
		return
	}

	if time.Now().Before(user.IncomeTime.Add(time.Hour * 2)) {
		nextTime := time.Since(user.IncomeTime.Add(time.Hour * 2))
		seconds := int(math.Round(math.Abs(nextTime.Seconds())))
		minutes := seconds / 60
		seconds -= minutes * 60
		hours := minutes / 60
		minutes -= hours * 60
		ctx.Answer(fmt.Sprintf("Приходи через %02d:%02d:%02d", hours, minutes, seconds))
		return
	}

	moneyIncome := decimal.NewFromInt(0)
	expIncome := decimal.NewFromInt(0)
	btcIncome := decimal.NewFromInt(0)

	if user.Business != nil {
		moneyIncome = moneyIncome.Add(user.Business.Income).Mul(user.Group.Multiplier)
	}
	if user.Maid != nil {
		expIncome = expIncome.Add(user.Maid.Income).Mul(user.Group.Multiplier)
	}
	if user.Miner != nil {
		btcIncome = btcIncome.Add(user.Miner.Income).Mul(user.Group.Multiplier)
	}

	waifus, err := psql.GetUserWaifus(user.ID)
	if err != nil {
		ctx.Error(err)
		return
	}

	for _, waifu := range waifus {
		moneyIncome = moneyIncome.Mul(waifu.MoneyBonus)
		expIncome = expIncome.Mul(waifu.ExpBonus)
		btcIncome = btcIncome.Mul(waifu.MoneyBonus)
	}

	var incomeText []string

	if moneyIncome.IntPart() > 0 {
		incomeText = append(incomeText, fmt.Sprintf("%s¥", utils.DecimalComma(&moneyIncome)))
	}
	if expIncome.IntPart() > 0 {
		incomeText = append(incomeText, fmt.Sprintf("%d опыта", expIncome.IntPart()))
	}
	if btcIncome.InexactFloat64() > 0 {
		incomeText = append(incomeText, fmt.Sprintf("%.6f₿", btcIncome.InexactFloat64()))
	}

	var passiveIncomeText []string
	if user.MoneyIncome.IntPart() > 0 {
		user.Balance = user.Balance.Add(user.MoneyIncome)
		passiveIncomeText = append(passiveIncomeText, fmt.Sprintf("%s¥", utils.DecimalComma(&user.MoneyIncome)))
		user.MoneyIncome = decimal.NewFromInt(0)
	}
	if user.ExpIncome > 0 {
		user.Exp += user.ExpIncome
		passiveIncomeText = append(passiveIncomeText, fmt.Sprintf("%d опыта", user.ExpIncome))
		user.ExpIncome = 0
	}
	if user.BtcIncome.InexactFloat64() > 0 {
		user.BTC = user.BTC.Add(user.BtcIncome)
		passiveIncomeText = append(passiveIncomeText, fmt.Sprintf("%.6f₿", user.BtcIncome.InexactFloat64()))
		user.BtcIncome = decimal.NewFromFloat(0.0000000)
	}

	user.Balance = user.Balance.Add(moneyIncome)
	user.Exp += int(expIncome.IntPart())
	user.Level, _ = psql.CountLevel(user.Exp)
	user.BTC = user.BTC.Add(btcIncome)
	user.IncomeTime = time.Now()

	database.PostgresDatabase.Save(user)

	out := []string{
		fmt.Sprintf("Ты собрал %s.", strings.Join(incomeText, ", ")),
	}

	if len(passiveIncomeText) > 0 {
		out = append(out, fmt.Sprintf("Пока тебя не было, было собрано %s.", strings.Join(passiveIncomeText, ", ")))
	}

	out = append(out, "Приходи через 02:00:00")

	ctx.Answer(strings.Join(out, "\n"))
}

func code(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	// user, err := database.Get
}

func vacancies(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	works, err := psql.GetAllWorks()

	if err != nil {
		ctx.Error(err)
		return
	}

	out := []string{
		"Список вакансий:",
	}

	for _, work := range works {
		out = append(out, fmt.Sprintf("%d) %s", work.ID, work.Name))
	}

	ctx.Answer(strings.Join(out, "\n"))
}

func getAJob(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
	if len(ctx.Args) == 0 {
		ctx.Answer("Недостаточно аргументов")
		return
	}

	user, err := psql.GetOrCreateUser(ctx.FromID, ctx.Msg.From.FirstName)
	if err != nil {
		ctx.Error(err)
		return
	}
	workId, err := strconv.Atoi(ctx.Args[0])
	if err != nil {
		ctx.Error(err)
		return
	}
	work, err := psql.GetWorkById(workId)
	if err != nil {
		ctx.Error(err)
		return
	}
	if user.Level < work.RequiredLevel {
		ctx.Answer("Уровень слишком низкий для этой работы!")
		return
	}
	user.WorkID = workId
	user.Work = work
	db.PostgresSQL.Save(user)
	ctx.Answer("Ты успешно устроился на работу!")
}

func aboutGroup(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) {
	user, err := psql.GetOrCreateUser(ctx.FromID, ctx.Msg.From.FirstName)
	if err != nil {
		ctx.Error(err)
		return
	}
	group := user.Group
	out := []string{
		fmt.Sprintf("%s, %s!", user.Greeting, user.Name),
		fmt.Sprintf("📝Твоя группа: %s", group.Name),
		fmt.Sprintf("📉Твоя скидка: %.0f%%", 100-group.Sale.InexactFloat64()*100),
		fmt.Sprintf("📈Твой множитель: x%.2f", group.Multiplier.InexactFloat64()),
		fmt.Sprintf("👩🏼Максимум вайфу: %d", group.MaxWaifus),
	}
	if group.IsVip {
		out = append(out, "🎏Доступ к ВИП функциям: ✅")
	}
	if group.IsAdmin {
		out = append(out, "🖥️Доступ к админ функциям: ✅")
	}
	if group.IsVip {
		out = append(out, "🔓Бета-тестер: ✅")
	}

	ctx.Answer(strings.Join(out, "\n"))
}
