package main

import (
	"context"
	"fmt"

	log "github.com/sirupsen/logrus"
	"github.com/tidbcloud/metering/pkg/errors"

	"github.com/tidbcloud/metering/pkg/common/models"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type Database struct {
	base *gorm.DB
}

func GetBillingReportDB(localFile string, repotertype ReporterType) (*Database, error) {
	var base *gorm.DB
	// open database and migrate the tables, if any error occurs, break and return the error
	errOptional := errors.OfNullable(nil).BreakIf(func() error {
		var innerErr error
		base, innerErr = gorm.Open(sqlite.Open(localFile+"?_busy_timeout=5000&_txlock=immediate"), &gorm.Config{
			Logger: logger.Default.LogMode(logger.Error),
		})
		return innerErr
	}).BreakIf(func() error {
		switch repotertype {
		case V2Reporter:
			return base.AutoMigrate(models.BillingReportV2{})
		case V1Reporter:
			return base.AutoMigrate(models.BillingReport{})
		case OldReporter:
			return base.AutoMigrate(models.BillingReport{})
		}
		return fmt.Errorf("unknown reporter type %v", repotertype)
	})

	if err := errOptional.Present(); err != nil {
		err = errors.Wrap(errors.GormDBError, fmt.Sprintf("GetBillingReportDB %s failed", localFile), err)
		log.Errorf("GetBillingReportDB %s failed: %v", localFile, err)
		return nil, err
	}

	return &Database{base: base}, nil
}

func (d Database) SaveBillingReports(ctx context.Context, reports []*models.BillingReport) error {
	return d.base.CreateInBatches(reports, len(reports)).Error
}

func (d Database) SaveBillingReportsV2(ctx context.Context, reports []*models.BillingReportV2) error {
	return d.base.CreateInBatches(reports, len(reports)).Error
}

func (d Database) ListBillingReports(ctx context.Context) ([]*models.BillingReport, error) {
	list := make([]*models.BillingReport, 0)

	err := d.base.Model(&models.BillingReport{}).Find(&list).Error

	return list, err
}

func (d Database) ListBillingReportsV2(ctx context.Context) ([]*models.BillingReportV2, error) {
	list := make([]*models.BillingReportV2, 0)
	err := d.base.Model(&models.BillingReportV2{}).Find(&list).Error

	return list, err
}

func (d Database) Close(ctx context.Context) {
	// don't need to close the database, it will be closed automatically
	// when object destroyed,the databse file will be closed
}
