<?php

namespace Formatrica\Submission\Pipeline;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Formatrica\Submission\Validation\Validation_Result;

/**
 * Mutable state threaded through the submission pipeline stages.
 *
 * Each stage reads what it needs and writes its results back onto the context,
 * so new stages slot in by position without reopening unrelated code. A stage
 * may finish() the pipeline early (e.g. user-registration returns its own
 * result); the runner stops and returns $result.
 */
final class Submission_Context
{
    /** @var array<string, mixed> */
    public array $request_data;

    /** @var array<string, mixed> */
    public array $files;

    /** @var array<string, mixed> Request context: ip_address, user_agent. */
    public array $context;

    /** @var array<string, mixed>|null Loaded form. */
    public ?array $form = null;

    /** @var array<string, mixed> Form config (fields + options). */
    public array $config = [];

    /** @var array<string, mixed> Hydrated options. */
    public array $options = [];

    public string $stored_ip = '';

    public ?Validation_Result $validation_result = null;

    /** @var array<string, mixed> Sanitised values. */
    public array $sanitised = [];

    /** @var array<string, string> Field errors. */
    public array $errors = [];

    /** @var array<int, array<string, mixed>> */
    public array $field_meta = [];

    public string $uuid = '';

    public ?int $submission_id = null;

    /** Set by Draft_Claim_Stage when this submission converts a saved draft. */
    public ?string $draft_uuid = null;

    /**
     * Set by Payment_Gate_Stage when a paid form defers to a gateway. Its
     * presence makes every side-effect stage self-skip (they re-run only after the
     * payment webhook confirms) and shapes the response into a payment redirect.
     * @var array<string,mixed>|null
     */
    public ?array $early_payment_response = null;

    /** @var array<string, mixed> */
    public array $email_result = [];

    public string $success_message = '';

    /** @var array<string, mixed> The response to return. */
    public array $result = [];

    private bool $finished = false;

    /**
     * @param array<string, mixed> $request_data
     * @param array<string, mixed> $files
     * @param array<string, mixed> $context
     */
    public function __construct(
        public int $form_id,
        array $request_data,
        array $files = [],
        array $context = []
    ) {
        $this->request_data = $request_data;
        $this->files = $files;
        $this->context = $context;
    }

    /**
     * Stop the pipeline and return $result (or the current result if omitted).
     *
     * @param array<string, mixed>|null $result
     */
    public function finish(?array $result = null): void
    {
        if ($result !== null) {
            $this->result = $result;
        }
        $this->finished = true;
    }

    public function is_finished(): bool
    {
        return $this->finished;
    }
}
