package db

import (
	"fmt"

	"github.com/pingcap/errors"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// sql
// CREATE TABLE `cases` (  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  `created_at` datetime(3) DEFAULT NULL,  `updated_at` datetime(3) DEFAULT NULL,  `deleted_at` datetime(3) DEFAULT NULL,  `name` longtext NOT NULL,  `oom_count` bigint(20) NOT NULL,  `sync_duration_sec` bigint(20) NOT NULL,  PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,  KEY `idx_cases_deleted_at` (`deleted_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=30001;
// CREATE TABLE `metrics` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  `created_at` datetime(3) DEFAULT NULL,  `updated_at` datetime(3) DEFAULT NULL,  `deleted_at` datetime(3) DEFAULT NULL,  `is_cdc_running` tinyint(1) NOT NULL,  `case_id` bigint(20) unsigned NOT NULL,  `name` longtext DEFAULT NULL,  `p85` double DEFAULT NULL,  `p95` double DEFAULT NULL,  `max` double DEFAULT NULL,  `raw_value` mediumtext DEFAULT NULL,  PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,  KEY `idx_metrics_deleted_at` (`deleted_at`),  CONSTRAINT `fk_metrics_case` FOREIGN KEY (`case_id`) REFERENCES `cases` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

var globalDB *gorm.DB

type Case struct {
	gorm.Model
	Name            string `gorm:"not null"`
	OOMCount        int    `gorm:"not null"`
	SyncDurationSec int64  `gorm:"not null"`
}

type Metric struct {
	gorm.Model
	IsCdcRunning bool `gorm:"not null"`
	CaseID       uint `gorm:"not null"`
	Case         Case
	Name         string  `gorm:"no null"`
	P85          float64 `gorm:"no null"`
	P95          float64 `gorm:"no null"`
	Max          float64 `gorm:"no null"`
	RawValue     string  `gorm:"type:MEDIUMTEXT"`
}

func InitDataBase(host, db, user, password string, port int) error {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, password, host, port, db)
	gdb, err := gorm.Open(mysql.Open(dsn), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true})
	if err != nil {
		return errors.Annotate(err, "failed to open database")
	}
	if err = gdb.AutoMigrate(&Case{}, &Metric{}); err != nil {
		return errors.Trace(err)
	}
	globalDB = gdb
	return nil
}

func AddCase(name string) (*Case, error) {
	boundaryCase := &Case{Name: name}
	if err := globalDB.Create(boundaryCase).Error; err != nil {
		return nil, errors.Trace(err)
	}
	return boundaryCase, nil
}

func UpdateCase(boundaryCase *Case) error {
	return errors.Trace(globalDB.Save(boundaryCase).Error)
}

func AddMetric(caseId uint, running bool, name string, p85, p95, max float64, raw string) (*Metric, error) {
	metric := &Metric{
		CaseID:       caseId,
		IsCdcRunning: running,
		Name:         name,
		P85:          p85,
		P95:          p95,
		Max:          max,
		RawValue:     raw,
	}
	if err := globalDB.Create(metric).Error; err != nil {
		return nil, errors.Trace(err)
	}
	return metric, nil
}
