package system

import (
	"context"
	"fmt"
	"sync/atomic"

	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
	"kra/internal/conf"
)

// Data is a small in-package test harness. Production repositories depend on
// Provider; tests keep the old, convenient field-based setup without coupling
// the system module back to internal/data.
type Data struct {
	gormDB        *reloadableDB
	redis         *reloadableRedis
	runtime       *conf.Runtime
	databaseReady atomic.Bool
}

func (d *Data) DB() *gorm.DB {
	if d == nil || d.gormDB == nil {
		return nil
	}
	return d.gormDB.DB()
}

func (d *Data) Database(string) (*gorm.DB, error) { return d.DB(), nil }
func (d *Data) DatabaseReady() bool               { return d != nil && d.databaseReady.Load() }
func (d *Data) Runtime() *conf.Runtime {
	if d == nil {
		return nil
	}
	return d.runtime
}

type reloadableDB struct{ db *gorm.DB }

func newReloadableDB(db *gorm.DB, _ any) *reloadableDB { return &reloadableDB{db: db} }
func (r *reloadableDB) DB() *gorm.DB {
	if r == nil {
		return nil
	}
	return r.db
}
func (r *reloadableDB) WithContext(ctx context.Context) *gorm.DB { return r.db.WithContext(ctx) }
func (r *reloadableDB) close() {
	if r == nil || r.db == nil {
		return
	}
	sqlDB, err := r.db.DB()
	if err == nil {
		_ = sqlDB.Close()
	}
}

type reloadableRedis struct{}

func newReloadableRedis(_ any) *reloadableRedis { return &reloadableRedis{} }

func openWithDriver(driver, dsn string) (*gorm.DB, error) {
	if driver != "sqlite" {
		return nil, fmt.Errorf("unsupported test database driver %q", driver)
	}
	return gorm.Open(sqlite.Open(dsn), &gorm.Config{})
}

func migrateAll(db *gorm.DB) error {
	for _, step := range Migrations() {
		if err := step.Migrate(db); err != nil {
			return err
		}
	}
	return nil
}
