package entity

import (
	"errors"
	"os"
	"sync"
	"time"

	"github.com/tidbcloud/tiinf/sdk/auditlog"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	"github.com/tidbcloud/auditlog/configs"
)

var (
	db         *gorm.DB
	initDBOnce sync.Once
)

func InitDB(cfg *configs.Config, migrate bool) error {
	var err error

	dsn := os.Getenv("DB_DSN")
	if dsn == "" && cfg != nil {
		dsn = cfg.DBDSN
	}
	if dsn == "" {
		dsn = os.Getenv("CONFIGOR_DBDSN")
	}
	if dsn == "" {
		return errors.New("db dsn is blank")
	}

	initDBOnce.Do(func() {
		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
		if err != nil {
			return
		}

		// run migration
		if migrate {
			err = db.AutoMigrate(&Event{}, &InternalEvent{}, &OrgAuditLogSettings{})
		}
	})

	return err
}

func GetDB() *gorm.DB {
	return db
}

type Model struct {
	ID        uint           `gorm:"primarykey" json:"id"`
	CreatedAt time.Time      `json:"created_at"`
	UpdatedAt time.Time      `json:"updated_at"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
}

type Event struct {
	Model

	Type                auditlog.EventType    `json:"type" gorm:"index"`
	EndsAt              time.Time             `json:"ends_at" gorm:"index"`
	OperatorType        auditlog.OperatorType `json:"operator_type"`
	OperatorID          uint64                `json:"operator_id"`
	OperatorEmail       string                `json:"operator_email"`
	OperatorIP          string                `json:"operator_ip"`
	OperatorLoginMethod string                `json:"operator_login_method"`
	OrgID               uint64                `json:"org_id" gorm:"index"`
	OrgName             string                `json:"org_name"`
	ProjectID           uint64                `json:"project_id"`
	ProjectName         string                `json:"project_name"`
	ClusterID           uint64                `json:"cluster_id"`
	ClusterName         string                `json:"cluster_name"`
	TraceID             string                `json:"trace_id"`
	Result              auditlog.Result       `json:"result"`
	Details             string                `json:"details"`
	ClusterType         auditlog.ClusterType  `json:"cluster_type"`
}

type InternalEvent struct {
	Model

	Type                auditlog.EventType    `json:"type" gorm:"index"`
	EndsAt              time.Time             `json:"ends_at" gorm:"index"`
	OperatorType        auditlog.OperatorType `json:"operator_type"`
	OperatorID          uint64                `json:"operator_id"`
	OperatorEmail       string                `json:"operator_email"`
	OperatorIP          string                `json:"operator_ip"`
	OperatorLoginMethod string                `json:"operator_login_method"`
	OrgID               uint64                `json:"org_id" gorm:"index"`
	OrgName             string                `json:"org_name"`
	ProjectID           uint64                `json:"project_id"`
	ProjectName         string                `json:"project_name"`
	ClusterID           uint64                `json:"cluster_id"`
	ClusterName         string                `json:"cluster_name"`
	TraceID             string                `json:"trace_id"`
	Result              auditlog.Result       `json:"result"`
	Details             string                `json:"details"`
	ClusterType         auditlog.ClusterType  `json:"cluster_type"`
}

type OrgAuditLogSettings struct {
	Model

	OrgID  uint64 `json:"org_id" gorm:"index"`
	Status int    `json:"status"`
}
