package mysql

import (
	"context"
	"strconv"
	"time"

	"gorm.io/gorm"

	v1 "github.com/pingcap-inc/pchub/model/v1"
)

type cloudBudget struct {
	db *gorm.DB
}

func newCloudBudget(ds *datastore) *cloudBudget {
	return &cloudBudget{db: ds.db}
}

func (u *cloudBudget) ListResourceBudgets(ctx context.Context, timeRange []time.Time, rid uint64) ([]*v1.BudgetCalcItem, error) {
	var res []*v1.BudgetCalcItem

	d := u.db.
		Model(&v1.CloudResourceBudget{}).
		Select("month, amount").
		Where("month >= ? AND month < ?", timeRange[0].Format("2006-01"), timeRange[1].Format("2006-01")).
		Where("resourceID = ?", rid).
		Order("month ASC").
		Scan(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (u *cloudBudget) GetMonthlyBudgetByResourecID(ctx context.Context, m string, rid uint64) (float64, error) {
	var res float64
	d := u.db.
		Model(&v1.CloudResourceBudget{}).
		Where("resourceID = ?", rid).
		Where("month = ?", m).
		Select("COALESCE(SUM(amount), 0) AS budget").
		Scan(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (u *cloudBudget) ListLatestFYResourceBudgets(ctx context.Context, rid uint64, years int) ([]*v1.BudgetCalcItem, error) {
	fyb, fye := GetFYBE(years)

	return u.ListResourceBudgets(ctx, []time.Time{fyb, fye}, rid)
}

func (u *cloudBudget) Create(ctx context.Context, budget *v1.CloudResourceBudget) (*v1.CloudResourceBudget, error) {
	return budget, u.db.Create(budget).Error
}

func (u *cloudBudget) UpdateBudget(_ context.Context, rid uint64, mon string, amount float64) error {
	return u.db.
		Model(&v1.CloudResourceBudget{}).
		Where("resourceID = ?", rid).
		Where("month = ?", mon).
		Update("amount", amount).
		Error
}

func (u *cloudBudget) Update(ctx context.Context, budget *v1.CloudResourceBudget) error {
	return u.db.Save(budget).Error
}

func (u *cloudBudget) ListByResourecID(ctx context.Context, lit int, rid uint64) (*[]v1.BudgetWithDate, error) {
	var queryRes []v1.BudgetWithDate
	t := time.Now()
	var nextM string
	if t.Month() == 12 {
		nextM = strconv.Itoa(t.Year()+1) + "-01"
	} else {
		nm := int(t.Month()) + 1
		if nm < 10 {
			nextM = strconv.Itoa(t.Year()) + "-0" + strconv.Itoa(nm)
		} else {
			nextM = strconv.Itoa(t.Year()) + "-" + strconv.Itoa(nm)
		}
	}

	d := u.db.
		Model(&v1.CloudResourceBudget{}).
		Where("resourceID = ?", rid).
		Where("month >= '2022-07' AND month < ?", nextM).
		Select("month AS dateStr, amount AS budget").
		Order("dateStr DESC").
		Limit(lit).
		Scan(&queryRes)

	return &queryRes, dbNotFoundErrorWrap(d.Error)
}

func (u *cloudBudget) ListPlanningByResourceID(ctx context.Context, rid uint64) (*[]v1.CloudResourceBudget, error) {
	var res []v1.CloudResourceBudget

	t := time.Now()
	var curM string
	if cm := int(t.Month()); cm < 10 {
		curM = strconv.Itoa(t.Year()) + "-0" + strconv.Itoa(cm)
	} else {
		curM = strconv.Itoa(t.Year()) + "-" + strconv.Itoa(cm)
	}

	d := u.db.
		Model(&v1.CloudResourceBudget{}).
		Where("resourceID = ?", rid).
		Where("month >= ?", curM).
		Order("month ASC").
		Find(&res)

	return &res, dbNotFoundErrorWrap(d.Error)
}
