<?php
/**
 * Public AJAX controller for Doli Training Management.
 *
 * @package DoliTrainingManagement
 */

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

/**
 * Registers public/admin AJAX actions and proxies requests to Dolibarr.
 *
 * Public catalog endpoints are intentionally available via `wp_ajax_nopriv_*`
 * without nonces (read-only proxy to the Dolibarr URL configured by the site admin).
 * `doli_training_management_create_inquiry` requires a nonce with the same action name.
 */
// phpcs:disable WordPress.Security.NonceVerification.Recommended,WordPress.Security.NonceVerification.Missing
class Doli_Training_Management_Ajax {

    /**
     * Shared proxy.
     *
     * @var Doli_Training_Management_Proxy
     */
    private $proxy;

    /**
     * Constructor.
     *
     * @param Doli_Training_Management_Proxy $proxy Proxy.
     */
    public function __construct($proxy) {
        $this->proxy = $proxy;
        $this->register_actions();
    }

    /**
     * Register public and authenticated AJAX actions.
     */
    private function register_actions() {
        $actions = array(
            'doli_training_management_get_constant'                => 'handle_get_constant',
            'doli_training_management_get_navigation_bootstrap'    => 'handle_get_navigation_bootstrap',
            'doli_training_management_get_categories'              => 'handle_get_categories',
            'doli_training_management_get_category_document'       => 'handle_get_category_document',
            'doli_training_management_get_training_document'       => 'handle_get_training_document',
            'doli_training_management_get_training'                => 'handle_get_training',
            'doli_training_management_get_products'                => 'handle_get_products',
            'doli_training_management_get_trainings_by_category'   => 'handle_get_trainings_by_category',
            'doli_training_management_get_trainings_catalog_bootstrap' => 'handle_get_trainings_catalog_bootstrap',
            'doli_training_management_get_training_sessions'       => 'handle_get_training_sessions',
            'doli_training_management_get_training_image_download' => 'handle_get_training_image_download',
            'doli_training_management_get_training_image_meta'     => 'handle_get_training_image_meta',
            'doli_training_management_create_inquiry'              => 'handle_create_inquiry',
        );

        foreach ($actions as $action => $handler) {
            add_action('wp_ajax_' . $action, array($this, $handler));
            add_action('wp_ajax_nopriv_' . $action, array($this, $handler));
        }
    }

    /**
     * Proxy GET constant value.
     */
    public function handle_get_constant() {
        $name = isset($_GET['name']) ? sanitize_text_field(wp_unslash($_GET['name'])) : '';
        $response = $this->proxy->get_constant($name);
        $this->send_json_result($response);
    }

    /**
     * Proxy catalog navigation bootstrap (single payload: nav constants + categories with photos).
     */
    public function handle_get_navigation_bootstrap() {
        $response = $this->proxy->get_navigation_bootstrap();
        $this->send_json_result($response);
    }

    /**
     * Proxy category list.
     */
    public function handle_get_categories() {
        $type  = isset($_GET['type']) ? absint($_GET['type']) : 28;
        $limit = isset($_GET['limit']) ? absint($_GET['limit']) : 10000;

        $response = $this->proxy->get_categories($type, $limit);
        $this->send_json_result($response);
    }

    /**
     * Proxy category document requests.
     */
    public function handle_get_category_document() {
        $modulepart = isset($_GET['modulepart']) ? sanitize_text_field(wp_unslash($_GET['modulepart'])) : '';
        $id         = isset($_GET['id']) ? absint($_GET['id']) : 0;
        $download   = isset($_GET['download']) ? sanitize_text_field(wp_unslash($_GET['download'])) : '';

        if ('category' !== $modulepart) {
            wp_send_json_error(array('message' => __('Invalid category document request.', 'doli-training-management')), 400);
        }

        if ('1' === $download) {
            $original_file = isset($_GET['original_file']) ? sanitize_text_field(wp_unslash((string) $_GET['original_file'])) : '';
            $response      = $this->proxy->get_category_document_download($original_file);
            $this->send_json_result($response);
            return;
        }

        $response = $this->proxy->get_category_documents_list($id);
        $this->send_json_result($response);
    }

    /**
     * Proxy training (or linked product) document list / download (DOLAPIKEY server-side).
     */
    public function handle_get_training_document() {
        $modulepart = isset($_GET['modulepart']) ? sanitize_text_field(wp_unslash($_GET['modulepart'])) : '';
        $download   = isset($_GET['download']) ? sanitize_text_field(wp_unslash($_GET['download'])) : '';

        if ('1' === $download) {
            $original_file = isset($_GET['original_file']) ? sanitize_text_field(wp_unslash((string) $_GET['original_file'])) : '';
            $response      = $this->proxy->get_training_document_download($modulepart, $original_file);
            $this->send_json_result($response);
            return;
        }

        $training_id = isset($_GET['training_id']) ? absint($_GET['training_id']) : 0;
        if ($training_id <= 0 && isset($_GET['id'])) {
            $training_id = absint($_GET['id']);
        }

        $response = $this->proxy->get_training_documents_list($training_id, $modulepart);
        $this->send_json_result($response);
    }

    /**
     * Proxy products.
     */
    public function handle_get_products() {
        $limit    = isset($_GET['limit']) ? absint($_GET['limit']) : 1000;
        $sort     = isset($_GET['sort']) ? sanitize_text_field(wp_unslash($_GET['sort'])) : 'ref';
        $order    = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : 'ASC';
        $category = isset($_GET['category']) ? absint($_GET['category']) : 0;

        $response = $this->proxy->get_products($limit, $sort, $order, $category);
        $this->send_json_result($response);
    }

    /**
     * Proxy trainings by category.
     */
    public function handle_get_trainings_by_category() {
        $category_id = isset($_GET['category_id']) ? absint($_GET['category_id']) : 0;
        $response    = $this->proxy->get_trainings_by_category($category_id);
        $this->send_json_result($response);
    }

    /**
     * Proxy full catalog trainings bootstrap (single payload: trainings + sessions + images).
     */
    public function handle_get_trainings_catalog_bootstrap() {
        $root_id = isset($_GET['root_navigation_category_id']) ? absint($_GET['root_navigation_category_id']) : 0;
        $response = $this->proxy->get_trainings_catalog_bootstrap($root_id);
        $this->send_json_result($response);
    }

    /**
     * Proxy single training details.
     */
    public function handle_get_training() {
        $training_id = isset($_GET['training_id']) ? absint($_GET['training_id']) : 0;
        if ($training_id <= 0 && isset($_GET['id'])) {
            $training_id = absint($_GET['id']);
        }
        $response = $this->proxy->get_training($training_id);
        $this->send_json_result($response);
    }

    /**
     * Proxy foreseen sessions.
     */
    public function handle_get_training_sessions() {
        $training_id = isset($_GET['training_id']) ? absint($_GET['training_id']) : 0;
        $response    = $this->proxy->get_training_sessions($training_id);
        $this->send_json_result($response);
    }

    /**
     * Proxy binary image download.
     */
    public function handle_get_training_image_download() {
        $training_id = isset($_GET['training_id']) ? absint($_GET['training_id']) : 0;
        $result      = $this->proxy->get_training_image_download_raw($training_id);

        if (is_wp_error($result)) {
            $this->send_wp_error($result);
        }

        $headers      = $result['headers'];
        $content_type = 'application/octet-stream';
        if (is_array($headers) && !empty($headers['content-type'])) {
            $content_type = (string) $headers['content-type'];
        } elseif (is_object($headers) && isset($headers['content-type'])) {
            $content_type = (string) $headers['content-type'];
        }

        status_header(200);
        header('Content-Type: ' . sanitize_text_field($content_type));
        echo $result['body']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        wp_die();
    }

    /**
     * Proxy image metadata fallback endpoint.
     */
    public function handle_get_training_image_meta() {
        $training_id = isset($_GET['training_id']) ? absint($_GET['training_id']) : 0;
        $response      = $this->proxy->get_training_image_meta($training_id);
        $this->send_json_result($response);
    }

    /**
     * Proxy inquiry creation.
     */
    public function handle_create_inquiry() {
        $source = $this->parse_inquiry_request_source();
        $nonce  = isset($source['nonce']) ? sanitize_text_field(wp_unslash((string) $source['nonce'])) : '';

        if ('' === $nonce || !wp_verify_nonce($nonce, 'doli_training_management_create_inquiry')) {
            wp_send_json_error(
                array(
                    'message' => __('Invalid security token. Please reload the page.', 'doli-training-management'),
                    'code'    => 'doli_training_management_invalid_nonce',
                ),
                403
            );
        }

        $payload  = $this->sanitize_inquiry_payload_fields($source);
        $response = $this->proxy->create_inquiry($payload);
        $this->send_json_result($response, 201);
    }

    /**
     * Raw inquiry request (JSON body merged with POST). Single read of php://input.
     *
     * @return array
     */
    private function parse_inquiry_request_source() {
        $raw_body = file_get_contents('php://input'); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
        $decoded  = json_decode((string) $raw_body, true);

        if (!is_array($decoded)) {
            $decoded = array();
        }

        return wp_parse_args($decoded, $_POST);
    }

    /**
     * Sanitize inquiry fields for the Dolibarr proxy (nonce already verified and excluded from outbound data).
     *
     * @param array $source Raw source.
     * @return array
     */
    private function sanitize_inquiry_payload_fields(array $source) {
        $contact_type = isset($source['contact_type']) ? sanitize_text_field(wp_unslash((string) $source['contact_type'])) : '';
        if (!in_array($contact_type, array('', 'mail', 'telephone'), true)) {
            $contact_type = '';
        }

        return array(
            'training_id'       => isset($source['training_id']) ? absint($source['training_id']) : 0,
            'training_label'    => isset($source['training_label']) ? sanitize_text_field(wp_unslash((string) $source['training_label'])) : '',
            'visitor_firstname' => isset($source['visitor_firstname']) ? sanitize_text_field(wp_unslash((string) $source['visitor_firstname'])) : '',
            'visitor_lastname'  => isset($source['visitor_lastname']) ? sanitize_text_field(wp_unslash((string) $source['visitor_lastname'])) : '',
            'visitor_email'     => isset($source['visitor_email']) ? sanitize_email(wp_unslash((string) $source['visitor_email'])) : '',
            'phone'             => isset($source['phone']) ? sanitize_text_field(wp_unslash((string) $source['phone'])) : '',
            'company'           => isset($source['company']) ? sanitize_text_field(wp_unslash((string) $source['company'])) : '',
            'preferred_date'    => isset($source['preferred_date']) ? sanitize_text_field(wp_unslash((string) $source['preferred_date'])) : '',
            'preferred_time'    => isset($source['preferred_time']) ? sanitize_text_field(wp_unslash((string) $source['preferred_time'])) : '',
            'contact_type'      => $contact_type,
            'message'           => isset($source['message']) ? sanitize_textarea_field(wp_unslash((string) $source['message'])) : '',
        );
    }

    /**
     * Send normalized JSON response.
     *
     * @param mixed $response Response value or WP_Error.
     * @param int   $success_code Success status code.
     */
    private function send_json_result($response, $success_code = 200) {
        if (is_wp_error($response)) {
            $this->send_wp_error($response);
        }

        wp_send_json_success($response, $success_code);
    }

    /**
     * Send normalized error payload.
     *
     * @param WP_Error $error Error instance.
     */
    private function send_wp_error($error) {
        $data    = $error->get_error_data();
        $status  = isset($data['status']) ? (int) $data['status'] : 500;
        $message = __('Request failed.', 'doli-training-management');
        $trace   = '';
        if (current_user_can('manage_options')) {
            $trace = $this->build_error_trace($data);
        }

        $payload = array(
            'message' => $message,
            'code'    => $error->get_error_code(),
        );

        if ('' !== $trace) {
            $payload['trace'] = $trace;
        }

        wp_send_json_error($payload, $status);
    }

    /**
     * Build a compact technical trace to help diagnose configuration/API issues.
     *
     * @param mixed $data Error data from WP_Error.
     * @return string
     */
    private function build_error_trace($data) {
        if (!is_array($data)) {
            return '';
        }

        $parts = array();

        if (isset($data['status'])) {
            $parts[] = 'status=' . (int) $data['status'];
        }

        if (isset($data['body'])) {
            $body = $data['body'];
            if (is_array($body)) {
                $json = wp_json_encode($body);
                if (is_string($json) && '' !== $json) {
                    $parts[] = 'body=' . substr($json, 0, 500);
                }
            } elseif (is_string($body) && '' !== $body) {
                $parts[] = 'body=' . substr($body, 0, 500);
            }
        } elseif (isset($data['rawBody']) && is_string($data['rawBody']) && '' !== $data['rawBody']) {
            $parts[] = 'body=' . substr($data['rawBody'], 0, 500);
        }

        return implode('; ', $parts);
    }
}
// phpcs:enable
