package db

import (
	"context"
	"database/sql"
	"errors"
	"github.com/huandu/go-sqlbuilder"
	"log/slog"
	"time"
	"xoxo-webserver/internal/domain/model"
	"xoxo-webserver/internal/random"
)

const jobLogTableName = "JOB_LOG"

var instanceName = random.NewString(16)
var jobLogStruct = sqlbuilder.NewStruct(new(model.JobLog)).For(dbFlavor)

func getLastJobLog(tx *sql.Tx) (*model.JobLog, error) {
	sb := jobLogStruct.SelectFrom(jobLogTableName).OrderBy("EXECUTION_TIME").Desc().Limit(1)
	q, args := sb.Build()
	row := tx.QueryRow(q, args...)
	var lastLog model.JobLog
	if err := row.Scan(jobLogStruct.Addr(&lastLog)...); err != nil && !errors.Is(err, sql.ErrNoRows) {
		slog.Error("Failed to get latest JOB_LOG", "error", err, "query", q, "args", args)
		return nil, err
	}
	return &lastLog, nil
}

func TryToLockJobLogTableAndCreateEntry(jobStart time.Time, duration time.Duration) (bool, error) {
	txOptions := sql.TxOptions{Isolation: sql.LevelSerializable}
	tx, err := db.BeginTx(context.Background(), &txOptions)
	if err != nil {
		slog.Error("Failed to create db transaction", "error", err)
		return false, err
	}
	lastLog, err := getLastJobLog(tx)
	if err != nil {
		return false, err
	}
	if !lastLog.IsOlder(jobStart, duration) {
		return false, nil
	}
	newLog := model.JobLog{jobStart, instanceName}
	ib := jobLogStruct.InsertInto(jobLogTableName, newLog)
	q, args := ib.Build()
	_, err = tx.Exec(q, args...)
	if err != nil {
		slog.Error("Failed to create JOB_LOG db entry", "error", err, "query", q, "args", args)
		return false, err
	}
	_ = tx.Commit()
	return true, nil
}

func createJobLogTableIfNotExists() {
	s := sqlbuilder.CreateTable(jobLogTableName).IfNotExists().
		Define("EXECUTION_TIME", "TIMESTAMP", "PRIMARY KEY").
		Define("EXECUTOR_ID", "TEXT").
		String()
	_, err := db.Exec(s)
	if err != nil {
		slog.Error("Could not create table", "jobLogTableName", jobLogTableName, "error", err)
	}
}
