// Copyright 2024 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0

package jobqueue

import (
	"github.com/stretchr/testify/assert"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"testing"
	"time"
)

func TestDeleteJob(t *testing.T) {
	gormDB, err := gorm.Open(sqlite.Open("file:unique_id?mode=memory&cache=shared"), &gorm.Config{})
	if err != nil {
		t.Fatalf("a error occurred while opening the database: %v", err)
	}
	t.Cleanup(func() {
		sqlDB, err := gormDB.DB()
		if err != nil {
			t.Fatalf("failed to get generic database object from GORM DB: %v", err)
		}
		_ = sqlDB.Close()
	})

	db := gormDB
	db.Logger = db.Logger.LogMode(4)

	assert.Nil(t, err)
	err = db.AutoMigrate(&JobPersistence{}, &JobLog{}, &JobStats{})
	assert.Nil(t, err)

	manager := NewManager()
	manager.SetDB(db)
	jobSyncer := NewJobSyncer(manager)

	// Erstelle einen Job zum Löschen
	runner := &CounterRunnable{}
	job := NewJob[CounterResult]("testJobID", runner)
	err = saveJob(job.GetPersistence(), db)
	assert.Nil(t, err)

	var count int64
	db.Model(&JobPersistence{}).Where("id = ?", "testJobID").Count(&count)
	assert.Equal(t, int64(1), count)

	// Lösche den Job
	err = jobSyncer.DeleteJob(job)
	assert.Nil(t, err)

	// Überprüfe, ob der Job gelöscht wurde
	db.Model(&JobPersistence{}).Where("id = ?", "testJobID").Count(&count)
	assert.Equal(t, int64(0), count)
}

func TestResetLogs(t *testing.T) {
	gormDB, err := gorm.Open(sqlite.Open("file:unique_id?mode=memory&cache=shared"), &gorm.Config{})
	if err != nil {
		t.Fatalf("a error occurred while opening the database: %v", err)
	}
	t.Cleanup(func() {
		sqlDB, err := gormDB.DB()
		if err != nil {
			t.Fatalf("failed to get generic database object from GORM DB: %v", err)
		}
		_ = sqlDB.Close()
	})

	db := gormDB

	db.Logger = db.Logger.LogMode(4)

	// Automatische Migration für benötigte Strukturen
	err = db.AutoMigrate(&JobPersistence{}, &JobLog{}, &JobStats{})
	assert.Nil(t, err)

	manager := NewManager()
	manager.SetDB(db)
	jobSyncer := NewJobSyncer(manager)

	// Erstelle einen Job und füge einige Logs hinzu
	runner := &CounterRunnable{}
	job := NewJob[CounterResult]("testJobID", runner)
	err = saveJob(job.GetPersistence(), db)
	assert.Nil(t, err)

	// Füge Logs zum Job hinzu
	for i := 0; i < 5; i++ {
		log := JobLog{JobID: job.GetID(), Result: "Test Message"}
		err = db.Create(&log).Error
		assert.Nil(t, err)
	}

	var logCount int64
	db.Model(&JobLog{}).Where("job_id = ?", job.GetID()).Count(&logCount)
	assert.Equal(t, int64(5), logCount)

	// Setze die Logs zurück
	err = jobSyncer.ResetLogs(job)
	assert.Nil(t, err)

	// Überprüfe, ob die Logs gelöscht wurden

	db.Model(&JobLog{}).Where("job_id = ?", job.GetID()).Count(&logCount)
	assert.Equal(t, int64(0), logCount)
}

func TestResetStats(t *testing.T) {
	gormDB, err := gorm.Open(sqlite.Open("file:unique_id?mode=memory&cache=shared"), &gorm.Config{})
	if err != nil {
		t.Fatalf("a error occurred while opening the database: %v", err)
	}
	t.Cleanup(func() {
		sqlDB, err := gormDB.DB()
		if err != nil {
			t.Fatalf("failed to get generic database object from GORM DB: %v", err)
		}
		_ = sqlDB.Close()
	})

	db := gormDB

	db.Logger = db.Logger.LogMode(4)

	// Automatische Migration für benötigte Strukturen
	err = db.AutoMigrate(&JobPersistence{}, &JobLog{}, &JobStats{})
	assert.Nil(t, err)

	manager := NewManager()
	manager.SetDB(db)
	jobSyncer := NewJobSyncer(manager)

	// Erstelle einen Job und setze einige Statistiken
	runner := &CounterRunnable{}
	job := NewJob[CounterResult]("testJobID", runner)
	err = saveJob(job.GetPersistence(), db)
	assert.Nil(t, err)

	// Aktualisiere die Job-Statistiken
	jobStats := &JobStats{
		JobID:        job.GetID(),
		RunCount:     5,
		SuccessCount: 3,
		ErrorCount:   2,
		TimeMetrics: TimeMetrics{
			AvgRunTime:   10 * time.Second,
			MaxRunTime:   15 * time.Second,
			MinRunTime:   5 * time.Second,
			TotalRunTime: 50 * time.Second,
		},
	}
	err = db.Save(jobStats).Error
	assert.Nil(t, err)

	// Setze die Statistiken zurück
	err = jobSyncer.ResetStats(job)
	assert.Nil(t, err)

	// Überprüfe, ob die Statistiken zurückgesetzt wurden
	var resetStats JobStats
	err = db.First(&resetStats, "job_id = ?", job.GetID()).Error
	assert.Nil(t, err)

	assert.Equal(t, int(0), resetStats.RunCount)
	assert.Equal(t, int(0), resetStats.SuccessCount)
	assert.Equal(t, int(0), resetStats.ErrorCount)
	assert.Equal(t, time.Duration(0), resetStats.TimeMetrics.AvgRunTime)
	assert.Equal(t, time.Duration(0), resetStats.TimeMetrics.MaxRunTime)
	assert.Equal(t, time.Duration(0), resetStats.TimeMetrics.MinRunTime)
	assert.Equal(t, time.Duration(0), resetStats.TimeMetrics.TotalRunTime)
}