package bootstrap

import (
	"database/sql"
	"fmt"

	seedrows "github.com/pingcap-inc/nexuscrm-contract/pkg/seedrows"
)

// ActionInputGuardRow is the subset of _System_ActionInputGuard consumed by
// the generic standard-action dispatcher at request time. Kept shallow so
// the dispatcher does not depend on the full bootstrap write path.
//
// Relocated verbatim to the contract module's seedrows package (Wave 0); this
// alias keeps existing importers compiling unchanged.
type ActionInputGuardRow = seedrows.ActionInputGuardRow

// GetActionInputGuards returns every active, non-deleted guard row for a
// standard-action Id, sorted by SortOrder ascending.
func GetActionInputGuards(db *sql.DB, standardActionID string) ([]ActionInputGuardRow, error) {
	query := fmt.Sprintf(
		`SELECT `+"`Condition`"+`, RequiredPermission, RequiredObject, RequiredOperation, ErrorMessage, GatedInput, SortOrder
		   FROM %s
		  WHERE StandardActionId = ? AND IsActive = 1 AND IsDeleted = 0
		  ORDER BY SortOrder ASC`,
		tableActionInputGuard,
	)
	rows, err := db.Query(query, standardActionID)
	if err != nil {
		return nil, fmt.Errorf("query action input guards: %w", err)
	}
	defer rows.Close()

	var out []ActionInputGuardRow
	for rows.Next() {
		var row ActionInputGuardRow
		var perm, object, operation, msg, gated sql.NullString
		if err := rows.Scan(&row.Condition, &perm, &object, &operation, &msg, &gated, &row.SortOrder); err != nil {
			return nil, fmt.Errorf("scan action input guard: %w", err)
		}
		if perm.Valid {
			row.RequiredPermission = perm.String
		}
		if object.Valid {
			row.RequiredObject = object.String
		}
		if operation.Valid {
			row.RequiredOperation = operation.String
		}
		if msg.Valid {
			row.ErrorMessage = msg.String
		}
		if gated.Valid {
			row.GatedInput = gated.String
		}
		out = append(out, row)
	}
	return out, rows.Err()
}

// GetActionInputGuardsForActions returns active guard rows for several
// standard-action IDs in one DB round trip, grouped by StandardActionId. Row
// ordering within each group matches GetActionInputGuards.
func GetActionInputGuardsForActions(db *sql.DB, standardActionIDs []string) (map[string][]ActionInputGuardRow, error) {
	actionIDs := uniqueActionIDs(standardActionIDs)
	out := make(map[string][]ActionInputGuardRow, len(actionIDs))
	for _, id := range actionIDs {
		out[id] = nil
	}
	if db == nil || len(actionIDs) == 0 {
		return out, nil
	}
	query := fmt.Sprintf(
		`SELECT StandardActionId, `+"`Condition`"+`, RequiredPermission, RequiredObject, RequiredOperation, ErrorMessage, GatedInput, SortOrder
		   FROM %s
		  WHERE StandardActionId IN (%s) AND IsActive = 1 AND IsDeleted = 0
		  ORDER BY StandardActionId ASC, SortOrder ASC`,
		tableActionInputGuard,
		actionReaderSQLPlaceholders(len(actionIDs)),
	)
	args := make([]interface{}, len(actionIDs))
	for i, id := range actionIDs {
		args[i] = id
	}
	rows, err := db.Query(query, args...)
	if err != nil {
		return nil, fmt.Errorf("query action input guards batch: %w", err)
	}
	defer rows.Close()

	for rows.Next() {
		var actionID string
		var row ActionInputGuardRow
		var perm, object, operation, msg, gated sql.NullString
		if err := rows.Scan(&actionID, &row.Condition, &perm, &object, &operation, &msg, &gated, &row.SortOrder); err != nil {
			return nil, fmt.Errorf("scan action input guard: %w", err)
		}
		if perm.Valid {
			row.RequiredPermission = perm.String
		}
		if object.Valid {
			row.RequiredObject = object.String
		}
		if operation.Valid {
			row.RequiredOperation = operation.String
		}
		if msg.Valid {
			row.ErrorMessage = msg.String
		}
		if gated.Valid {
			row.GatedInput = gated.String
		}
		out[actionID] = append(out[actionID], row)
	}
	return out, rows.Err()
}
