package persistence

import (
	"context"
	"database/sql"
	"errors"
)

func (r *SchemaRepository) permissionStateDirectWriterShouldRun(
	ctx context.Context,
	writerID string,
) bool {
	if r == nil {
		return false
	}
	if permissionStateDirectWriterIsActive(ctx, writerID) {
		return false
	}
	if r.permissionStateDirectCoordinator == nil {
		return true
	}
	return r.permissionStateDirectCoordinator.shouldRun(ctx, writerID)
}

func (r *SchemaRepository) runPermissionStateDirectWriter(
	ctx context.Context,
	writerID string,
	targets []permissionStateDirectTarget,
	mutation func(context.Context) error,
) error {
	coordinator := r.permissionStateDirectCoordinator
	if coordinator == nil {
		return errPermissionStateDirectWriterCoordinatorRequired
	}
	if !coordinator.shouldRun(ctx, writerID) {
		return mutation(ctx)
	}
	return coordinator.runProjected(
		ctx,
		writerID,
		targets,
		r.getExecutor,
		mutation,
	)
}

func (r *SchemaRepository) getExecutor(ctx context.Context) Executor {
	if tx, ok := ctx.Value(txContextKey{}).(*sql.Tx); ok && tx != nil {
		return tx
	}
	return r.db
}

func (r *SchemaRepository) requirePermissionStateOwnedExecutor(
	ctx context.Context,
	value interface{},
) error {
	coordinator := r.permissionStateDirectCoordinator
	if coordinator == nil {
		return errPermissionStateDirectWriterCoordinatorRequired
	}
	if value == nil {
		return nil
	}
	explicit, ok := value.(*sql.Tx)
	active, _ := coordinator.transactions.ExtractTx(ctx).(*sql.Tx)
	if !ok || explicit == nil || active == nil || explicit != active ||
		!coordinator.transactions.ownsPessimisticTx(ctx) {
		return errors.New(
			"persistence: direct schema writer requires the coordinator-owned pessimistic transaction",
		)
	}
	return nil
}

func (r *SchemaRepository) permissionStateOwnedTransaction(ctx context.Context) interface{} {
	if r.permissionStateDirectCoordinator == nil {
		return nil
	}
	return r.permissionStateDirectCoordinator.transactions.ExtractTx(ctx)
}
