<?php

namespace Formatrica\Submission;

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

use Formatrica\Email\Email_Service;
use Formatrica\Forms\Form_Repository;
use Formatrica\Submission\Pipeline\Stages\After_Submission_Stage;
use Formatrica\Submission\Pipeline\Stages\Anti_Bot_Stage;
use Formatrica\Submission\Pipeline\Stages\Before_Submission_Stage;
use Formatrica\Submission\Pipeline\Stages\Build_Context_Stage;
use Formatrica\Submission\Pipeline\Stages\Captcha_Stage;
use Formatrica\Submission\Pipeline\Stages\Filter_Request_Stage;
use Formatrica\Submission\Pipeline\Stages\Form_Lookup_Stage;
use Formatrica\Submission\Pipeline\Stages\Integration_Dispatch_Stage;
use Formatrica\Submission\Pipeline\Stages\Notification_Email_Stage;
use Formatrica\Submission\Pipeline\Stages\Persistence_Stage;
use Formatrica\Submission\Pipeline\Stages\Rate_Limit_Stage;
use Formatrica\Submission\Pipeline\Stages\Success_Response_Stage;
use Formatrica\Submission\Pipeline\Stages\Token_Validation_Stage;
use Formatrica\Submission\Pipeline\Stages\User_Registration_Stage;
use Formatrica\Submission\Pipeline\Stages\Validation_Error_Stage;
use Formatrica\Submission\Pipeline\Stages\Validation_Stage;
use Formatrica\Submission\Pipeline\Submission_Context;
use Formatrica\Submission\Pipeline\Submission_Pipeline;
use Formatrica\Submission\Security\Captcha_Service;
use Formatrica\Submission\Security\IP_Handler;
use Formatrica\Submission\Security\Rate_Limiter;
use Formatrica\Submission\Validation\Field_Validator;
use Formatrica\Submission\File\File_Uploader;

/**
 * Orchestrates form submission processing as an ordered pipeline of single-
 * responsibility stages (see app/Submission/Pipeline). New stages slot in by
 * position without reopening unrelated code. This class only wires the stages
 * with their collaborators and runs them.
 */
final class Submission_Service
{
    private Form_Repository $forms;
    private Submission_Repository $submissions;
    private Email_Service $email;
    private Field_Validator $field_validator;
    private File_Uploader $file_uploader;
    private Captcha_Service $captcha_service;
    private Rate_Limiter $rate_limiter;
    private IP_Handler $ip_handler;
    private Integration_Queue $integration_queue;

    public function __construct(
        ?Form_Repository $forms = null,
        ?Submission_Repository $submissions = null,
        ?Email_Service $email = null,
        ?Field_Validator $field_validator = null,
        ?File_Uploader $file_uploader = null,
        ?Captcha_Service $captcha_service = null,
        ?Rate_Limiter $rate_limiter = null,
        ?IP_Handler $ip_handler = null,
        ?Integration_Queue $integration_queue = null
    ) {
        $this->forms = $forms ?? new Form_Repository();
        $this->submissions = $submissions ?? new Submission_Repository();
        $this->email = $email ?? new Email_Service();
        $this->field_validator = $field_validator ?? new Field_Validator();
        $this->file_uploader = $file_uploader ?? new File_Uploader();
        $this->captcha_service = $captcha_service ?? new Captcha_Service();
        $this->rate_limiter = $rate_limiter ?? new Rate_Limiter();
        $this->ip_handler = $ip_handler ?? new IP_Handler();
        $this->integration_queue = $integration_queue ?? new Integration_Queue();
    }

    /**
     * Handle a form submission by running the pipeline.
     *
     * @param array<string, mixed> $request_data
     * @param array<string, mixed> $context
     * @param array<string, mixed> $files
     * @return array<string, mixed>
     * @throws Exception\Submission_Exception
     */
    public function handle(int $form_id, array $request_data, array $context = [], array $files = []): array
    {
        $ctx = new Submission_Context($form_id, $request_data, $files, $context);

        (new Submission_Pipeline($this->build_stages()))->process($ctx);

        return $ctx->result;
    }

    /**
     * The ordered submission pipeline. Order is behaviour-significant.
     *
     * @return list<\Formatrica\Submission\Pipeline\Submission_Stage>
     */
    private function build_stages(): array
    {
        // Keyed by stable slugs so edition extensions can insert relative to
        // named stages (Phase 6, plan §6.8): the Pro provider registers a
        // Pipeline_Extensions callback that adds draft claim/finalize and the
        // payment gate. This Free file names no Pro stage.
        $stages = [
            'form_lookup'            => new Form_Lookup_Stage($this->forms),
            'token_validation'       => new Token_Validation_Stage(),
            'anti_bot'               => new Anti_Bot_Stage(),
            'build_context'          => new Build_Context_Stage($this->ip_handler),
            'captcha'                => new Captcha_Stage($this->captcha_service),
            'filter_request'         => new Filter_Request_Stage(),
            'before_submission'      => new Before_Submission_Stage(),
            'rate_limit'             => new Rate_Limit_Stage($this->rate_limiter),
            'validation'             => new Validation_Stage($this->field_validator, $this->file_uploader),
            'validation_error'       => new Validation_Error_Stage(),
            'user_registration'      => new User_Registration_Stage(),
            'persistence'            => new Persistence_Stage($this->submissions),
            'notification_email'     => new Notification_Email_Stage($this->email),
            'success_response'       => new Success_Response_Stage(),
            'integration_dispatch'   => new Integration_Dispatch_Stage($this->integration_queue),
            'after_submission'       => new After_Submission_Stage(),
        ];

        return array_values(\Formatrica\Submission\Pipeline\Pipeline_Extensions::apply($stages));
    }

    /**
     * Get honeypot field name
     */
    public static function honeypot_field_name(int $form_id): string
    {
        $seed = wp_salt('nonce') . '|formatrica|h';
        return substr(hash('sha256', $seed . '|' . $form_id), 5, 24);
    }

    /**
     * Get timestamp field name
     */
    public static function timestamp_field_name(int $form_id): string
    {
        $seed = wp_salt('nonce') . '|formatrica|t';
        return substr(hash('sha256', $seed . '|' . $form_id), 11, 24);
    }
}
