/**
 * Batch Apex class for {describe the batch operation}.
 * Processes {SObject} records in configurable batch sizes.
 * Implements Database.Stateful to track cumulative results across chunks.
 * @author {Author}
 *
 * @example
 * // Execute with default batch size
 * Database.executeBatch(new {ClassName}());
 *
 * // Execute with custom batch size
 * Database.executeBatch(new {ClassName}(), 100);
 */
public with sharing class {ClassName} implements Database.Batchable<SObject>, Database.Stateful {

    // ─── Constants ───────────────────────────────────────────────────────
    private static final Integer DEFAULT_BATCH_SIZE = 200;

    // ─── Stateful Tracking ───────────────────────────────────────────────
    private Integer totalProcessed = 0;
    private Integer totalErrors = 0;
    private List<String> errorMessages = new List<String>();

    // ─── Constructor ─────────────────────────────────────────────────────

    /**
     * Default constructor
     */
    public {ClassName}() {
        // Default configuration
    }

    // ─── Batchable Interface ─────────────────────────────────────────────

    /**
     * Defines the scope of records to process.
     *              Uses Database.QueryLocator for efficient large-dataset processing.
     * @param bc The batch context
     * @return QueryLocator for the records to process
     */
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator([
            SELECT Id, Name
            // TODO: Add fields needed for processing
            FROM {SObject}
            // TODO: Add WHERE clause to scope the records
            WITH USER_MODE
        ]);
    }

    /**
     * Processes each batch of records.
     *              Uses Database.update with allOrNone=false for partial success handling.
     * @param bc The batch context
     * @param scope List of {SObject} records in the current batch
     */
    public void execute(Database.BatchableContext bc, List<{SObject}> scope) {
        List<{SObject}> recordsToUpdate = new List<{SObject}>();

        for ({SObject} record : scope) {
            // TODO: Apply business logic to each record
            recordsToUpdate.add(record);
        }

        if (!recordsToUpdate.isEmpty()) {
            List<Database.SaveResult> results = Database.update(recordsToUpdate, false);
            processResults(results);
        }
    }

    /**
     * Performs post-processing after all batches complete.
     *              Logs a summary of the batch execution.
     * @param bc The batch context
     */
    public void finish(Database.BatchableContext bc) {
        String summary = String.format(
            '{0} completed. Processed: {1}, Errors: {2}',
            new List<Object>{
                {ClassName}.class.getName(),
                totalProcessed,
                totalErrors
            }
        );

        System.debug(LoggingLevel.INFO, summary);

        if (!errorMessages.isEmpty()) {
            System.debug(LoggingLevel.ERROR, 'Error details: ' + String.join(errorMessages, '\n'));
        }

        // TODO: Send completion notification email or post to chatter if needed
    }

    // ─── Private Helpers ─────────────────────────────────────────────────

    /**
     * Processes Database.SaveResult list, tracking successes and failures
     * @param results List of SaveResult from a DML operation
     */
    private void processResults(List<Database.SaveResult> results) {
        for (Database.SaveResult result : results) {
            if (result.isSuccess()) {
                totalProcessed++;
            } else {
                totalErrors++;
                for (Database.Error err : result.getErrors()) {
                    errorMessages.add(
                        'Record ' + result.getId() + ': ' +
                        err.getStatusCode() + ' - ' + err.getMessage()
                    );
                }
            }
        }
    }

    // ─── Static Helpers ──────────────────────────────────────────────────

    /**
     * Convenience method to execute with default batch size
     * @return The batch job Id
     */
    public static Id run() {
        return Database.executeBatch(new {ClassName}(), DEFAULT_BATCH_SIZE);
    }
}
