<?php
/**
 * Wally Monitor - REST API
 *
 * Provides REST endpoints for programmatic access to accessibility data.
 * Namespace: wally-monitor/v1
 *
 * Endpoints:
 *   GET  /wally-monitor/v1/scan?url=<url>          — Run scan on a URL
 *   GET  /wally-monitor/v1/report?url=<url>         — Get latest report
 *   GET  /wally-monitor/v1/history?limit=<n>         — Get scan history
 *   GET  /wally-monitor/v1/status                    — Plugin status
 *   POST /wally-monitor/v1/schedule                  — Manage cron schedule
 *
 * @package    WallyMonitor
 * @subpackage Includes
 * @since      1.1.0
 */

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

class Wally_Rest_API {

    /** @var string REST namespace */
    const REST_NAMESPACE = 'wally-monitor/v1';

    /**
     * Initialize REST API routes.
     */
    public static function init() {
        add_action( 'rest_api_init', array( new self(), 'register_routes' ) );
    }

    /**
     * Register all REST routes.
     */
    public function register_routes() {
        // GET /scan
        register_rest_route( self::REST_NAMESPACE, '/scan', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'scan' ),
            'permission_callback' => array( $this, 'check_admin_permission' ),
            'args'                => array(
                'url' => array(
                    'required'          => false,
                    'type'              => 'string',
                    'sanitize_callback' => 'esc_url_raw',
                    'description'       => 'URL para analisar. Se omitida, analisa a home.',
                ),
                'save' => array(
                    'required' => false,
                    'type'     => 'boolean',
                    'default'  => false,
                ),
            ),
        ) );

        // GET /report
        register_rest_route( self::REST_NAMESPACE, '/report', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_report' ),
            'permission_callback' => array( $this, 'check_admin_permission' ),
            'args'                => array(
                'url' => array(
                    'required'          => false,
                    'type'              => 'string',
                    'sanitize_callback' => 'esc_url_raw',
                ),
            ),
        ) );

        // GET /history
        register_rest_route( self::REST_NAMESPACE, '/history', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_history' ),
            'permission_callback' => array( $this, 'check_admin_permission' ),
            'args'                => array(
                'limit' => array(
                    'required' => false,
                    'type'     => 'integer',
                    'default'  => 10,
                    'minimum'  => 1,
                    'maximum'  => 100,
                ),
            ),
        ) );

        // GET /status
        register_rest_route( self::REST_NAMESPACE, '/status', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_status' ),
            'permission_callback' => array( $this, 'check_admin_permission' ),
        ) );

        // POST /schedule
        register_rest_route( self::REST_NAMESPACE, '/schedule', array(
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => array( $this, 'manage_schedule' ),
            'permission_callback' => array( $this, 'check_admin_permission' ),
            'args'                => array(
                'enabled' => array(
                    'required' => true,
                    'type'     => 'boolean',
                ),
                'frequency' => array(
                    'required' => false,
                    'type'     => 'string',
                    'default'  => 'weekly',
                    'enum'     => array( 'hourly', 'daily', 'weekly', 'monthly' ),
                ),
            ),
        ) );

        // GET /rules
        register_rest_route( self::REST_NAMESPACE, '/rules', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_rules' ),
            'permission_callback' => 'is_user_logged_in',
        ) );
    }

    // ─── Permission Check ───────────────────────────────────────────────

    /**
     * Verify the user has admin capabilities.
     *
     * @param WP_REST_Request $request Request object.
     * @return bool|WP_Error
     */
    public function check_admin_permission( $request ) {
        if ( ! current_user_can( 'manage_options' ) ) {
            return new WP_Error(
                'rest_forbidden',
                __( 'Permissão negada. Requer manage_options.', 'wally-monitor' ),
                array( 'status' => 403 )
            );
        }
        return true;
    }

    // ─── Endpoint: scan ─────────────────────────────────────────────────

    /**
     * Run a server-side accessibility scan.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function scan( $request ) {
        $url  = $request->get_param( 'url' ) ?: home_url( '/' );
        $save = $request->get_param( 'save' );

        $result = $this->analyze_url( $url );

        if ( is_wp_error( $result ) ) {
            return $result;
        }

        if ( $save ) {
            $db = Wally_Database::get_instance();
            $db->insert_report(
                $url,
                $result,
                $result['summary']['score'],
                $result['summary']['totalProblems']
            );

            $history = get_option( 'wally_monitor_history', array() );
            array_unshift( $history, array(
                'timestamp'      => current_time( 'mysql' ),
                'user_id'        => get_current_user_id(),
                'score'          => $result['summary']['score'],
                'total_problems' => $result['summary']['totalProblems'],
                'url'            => $url,
                'source'         => 'REST API',
                'analysis_mode'  => isset( $result['summary']['analysisMode'] ) ? sanitize_key( $result['summary']['analysisMode'] ) : 'wcag',
            ) );
            update_option( 'wally_monitor_history', array_slice( $history, 0, 100 ), false );
        }

        return rest_ensure_response( array(
            'success' => true,
            'data'    => $result,
        ) );
    }

    // ─── Endpoint: report ───────────────────────────────────────────────

    /**
     * Get latest saved report.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_report( $request ) {
        $url = $request->get_param( 'url' );
        $db  = Wally_Database::get_instance();

        if ( $url ) {
            $data = $db->get_latest_report( $url );
        } else {
            $data = $this->get_latest_any_report();
        }

        if ( ! $data ) {
            return new WP_Error(
                'no_report',
                __( 'Nenhum relatório encontrado.', 'wally-monitor' ),
                array( 'status' => 404 )
            );
        }

        return rest_ensure_response( array(
            'success' => true,
            'data'    => $data,
        ) );
    }

    // ─── Endpoint: history ──────────────────────────────────────────────

    /**
     * Get scan history.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_history( $request ) {
        $limit   = $request->get_param( 'limit' );
        $history = get_option( 'wally_monitor_history', array() );
        $history = array_slice( $history, 0, $limit );

        return rest_ensure_response( array(
            'success' => true,
            'count'   => count( $history ),
            'data'    => $history,
        ) );
    }

    // ─── Endpoint: status ───────────────────────────────────────────────

    /**
     * Get plugin status.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_status( $request ) {
        $history   = get_option( 'wally_monitor_history', array() );
        $cron_next = wp_next_scheduled( 'wally_monitor_cron_scan' );

        $status = array(
            'plugin_version' => defined( 'WALLY_MONITOR_VERSION' ) ? WALLY_MONITOR_VERSION : 'N/A',
            'db_version'     => get_option( 'wally_monitor_db_version', 'N/A' ),
            'total_scans'    => count( $history ),
            'last_scan'      => ! empty( $history ) ? $history[0] : null,
            'cron'           => array(
                'enabled'   => Wally_Cron::is_enabled(),
                'frequency' => get_option( 'wally_monitor_cron_frequency', 'not set' ),
                'next_run'  => $cron_next ? date_i18n( 'Y-m-d H:i:s', $cron_next ) : null,
            ),
            'settings'       => get_option( 'wally_monitor_settings', array() ),
            'capabilities'   => array(
                'server_side_rules' => 25,
                'client_side_rules' => 48,
                'nbr_17225_rules'   => 35,
                'quick_fix_rules'   => 37,
            ),
        );

        return rest_ensure_response( array(
            'success' => true,
            'data'    => $status,
        ) );
    }

    // ─── Endpoint: schedule ─────────────────────────────────────────────

    /**
     * Enable or disable cron schedule.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function manage_schedule( $request ) {
        $enabled   = $request->get_param( 'enabled' );
        $frequency = $request->get_param( 'frequency' );

        if ( $enabled ) {
            Wally_Cron::enable( $frequency );
            $next = wp_next_scheduled( 'wally_monitor_cron_scan' );

            return rest_ensure_response( array(
                'success'   => true,
                // translators: %s is the cron frequency (e.g. daily, weekly).
                'message'   => sprintf( __( 'Agendamento ativado: %s', 'wally-monitor' ), $frequency ),
                'next_run'  => $next ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $next ) : null,
            ) );
        } else {
            Wally_Cron::disable();

            return rest_ensure_response( array(
                'success' => true,
                'message' => __( 'Agendamento desativado.', 'wally-monitor' ),
            ) );
        }
    }

    // ─── Endpoint: rules ────────────────────────────────────────────────

    /**
     * Get list of all accessibility rules the plugin checks.
     * Public endpoint — no authentication required.
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_rules( $request ) {
        $rules = array(
            'wcag_rules' => array(
                'description' => 'Regras WCAG 2.2',
                'count'       => '80+',
                'engine'      => 'client-side (JavaScript)',
            ),
            'custom_rules' => array(
                'description' => 'Regras customizadas WordPress',
                'count'       => 13,
                'engine'      => 'client-side (JavaScript)',
                'rules'       => array(
                    'wally-empty-alt-images', 'wally-empty-buttons', 'wally-wordpress-galleries',
                    'wally-media-accessibility', 'wally-wordpress-forms', 'wally-heading-hierarchy',
                    'wally-table-accessibility', 'wally-cover-block-contrast', 'wally-navigation-structure',
                    'wally-site-logo', 'wally-search-widget', 'wally-custom-html-blocks', 'wally-embed-accessibility',
                ),
            ),
            'nbr_17225' => array(
                'description' => 'Regras NBR 17.225 (Norma Brasileira)',
                'count'       => 48,
                'engine'      => 'client-side (JavaScript)',
                'groups'      => array(
                    'wcag_2_2'   => 7,
                    'language'   => 4,
                    'keyboard'   => 5,
                    'visual'     => 8,
                    'semantics'  => 8,
                    'forms'      => 3,
                ),
            ),
            'server_side' => array(
                'description' => 'Regras server-side (CLI/Cron/REST)',
                'count'       => 25,
                'engine'      => 'server-side (regex)',
            ),
        );

        return rest_ensure_response( array(
            'success'     => true,
            'total_rules' => '208+',
            'data'        => $rules,
        ) );
    }

    // ─── Internal Helpers ───────────────────────────────────────────────

    /**
     * Run server-side regex analysis on a URL.
     *
     * @param string $url URL to analyze.
     * @return array|WP_Error
     */
    private function analyze_url( $url ) {
        // SSRF protection — validate URL before fetching
        $url_check = wally_monitor_validate_url( $url );
        if ( is_wp_error( $url_check ) ) {
            return new WP_Error(
                'ssrf_blocked',
                $url_check->get_error_message(),
                array( 'status' => 403 )
            );
        }

        $response = wp_remote_get( $url, array(
            'timeout'   => 30,
            'sslverify' => apply_filters( 'wally_monitor_sslverify', true ),
        ) );

        if ( is_wp_error( $response ) ) {
            return new WP_Error(
                'fetch_error',
                sprintf( 'Falha ao acessar %s: %s', $url, $response->get_error_message() ),
                array( 'status' => 502 )
            );
        }

        $code = wp_remote_retrieve_response_code( $response );
        if ( $code >= 400 ) {
            return new WP_Error(
                'http_error',
                sprintf( 'HTTP %d ao acessar %s', $code, $url ),
                array( 'status' => $code )
            );
        }

        $html = wp_remote_retrieve_body( $response );

        // DOMDocument-based accessibility checks (replaces regex)
        $checker = new Wally_HTML_Checker( $html );
        $result  = $checker->run_core_checks();

        $violations = $result['violations'];
        $penalty    = $result['penalty'];
        $score      = Wally_HTML_Checker::calculate_score( $penalty );

        return array(
            'url'       => $url,
            'scan_date' => current_time( 'mysql' ),
            'method'    => 'server-side (DOMDocument)',
            'note'      => 'Análise server-side é limitada. Use interface web para WCAG 2.2 + NBR 17.225 completos.',
            'summary'   => array(
                'score'          => $score,
                'totalProblems'  => array_sum( array_column( $violations, 'count' ) ),
                'rulesViolated'  => count( $violations ),
                'rulesChecked'   => 12,
            ),
            'violations' => $violations,
        );
    }

    /**
     * Get the latest report from any URL.
     *
     * @return array|null
     */
    private function get_latest_any_report() {
        return Wally_Database::get_instance()->get_latest_any_report();
    }
}
