package runtimeworker

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"github.com/nexuscrm/audit"
	"github.com/nexuscrm/backend/internal/runtimeconfig"
	database "github.com/nexuscrm/db"
	eventfeature "github.com/nexuscrm/events"
	"github.com/nexuscrm/persistence"
)

const platformCommandNetworkTimeout = 30 * time.Second

func openWorkerDatabase(ctx context.Context, options database.PoolOptions, purpose string) (*sql.DB, error) {
	db, err := database.OpenDBFromEnv(options)
	if err != nil {
		return nil, err
	}
	if err := db.PingContext(ctx); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("%s: database readiness: %w", purpose, err)
	}
	return db, nil
}

// openWorkerConnection preserves the immutable driver/DSN authority needed by
// long-running workers to lazily open bounded independent pools. The primary
// worker pool remains the authority for business processing and readiness.
func openWorkerConnection(ctx context.Context, options database.PoolOptions, purpose string) (*database.TiDBConnection, error) {
	connection, err := database.NewConnectionContext(ctx, options)
	if err != nil {
		return nil, fmt.Errorf("%s: database readiness: %w", purpose, err)
	}
	return connection, nil
}

func productionWorkerPool(role runtimeconfig.WorkerRole) database.PoolOptions {
	options := database.PoolOptions{
		MaxOpenConns:      role.DBMaxOpenConns,
		MaxIdleConns:      role.DBMaxIdleConns,
		ConnMaxLifetime:   5 * time.Minute,
		ConnMaxIdleTime:   3 * time.Minute,
		InterpolateParams: role.WorkFamily == persistence.RuntimePlatformCommandExecutionWorkFamily,
	}
	switch role.WorkFamily {
	case audit.AuditHistoryFanoutWorkFamily:
		// Audit transactions are short. Bound silent network waits, including
		// COMMIT and session cleanup, so the existing lease loop can recover.
		options.NetworkTimeout = 5 * time.Second
	case persistence.RuntimePlatformCommandExecutionWorkFamily, eventfeature.RuntimeRecordEventDispatchWorkFamily:
		// A silent read holds the effect transaction and its work fence even
		// after lease expiry. Bound each driver I/O, including COMMIT/ROLLBACK;
		// successful multi-statement effects keep their existing duration policy.
		options.NetworkTimeout = platformCommandNetworkTimeout
	}
	return options
}

func repairWorkerPool() database.PoolOptions {
	return database.PoolOptions{
		MaxOpenConns:    2,
		MaxIdleConns:    1,
		ConnMaxLifetime: time.Minute,
		ConnMaxIdleTime: time.Minute,
	}
}

// runtimeWorkerObservationPool is a fixed L0 diagnostic budget. It is separate
// from the primary worker pool so an exact queue sample can never consume a
// connection reserved for claims, effects, heartbeats, or ownership checks.
func runtimeWorkerObservationPool() database.PoolOptions {
	return database.PoolOptions{
		MaxOpenConns:    1,
		MaxIdleConns:    1,
		ConnMaxLifetime: 5 * time.Minute,
		ConnMaxIdleTime: 3 * time.Minute,
	}
}

func configuredWorkOwnership(role runtimeconfig.WorkerRole) persistence.RuntimeWorkOwnership {
	return persistence.RuntimeWorkOwnership{
		WorkFamily:          role.WorkFamily,
		DeploymentID:        role.DeploymentID,
		WorkerReleaseDigest: role.WorkerReleaseDigest,
		OwnershipEpoch:      role.OwnershipEpoch,
	}
}
