<?php

/**
 * LinkCentral REST API Class
 *
 * This class handles all REST API functionality for LinkCentral, including
 * post type fields, admin settings, and any future API endpoints.
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// Exit if accessed directly
// Include the Link Manager
require_once LINKCENTRAL_PLUGIN_DIR . 'includes/utils/link-manager.php';
class LinkCentral_REST_API {
    /**
     * Link Manager instance
     * @var LinkCentral_Link_Manager
     */
    private $link_manager;

    /**
     * Initialize the class by registering REST API fields
     */
    public function init() {
        $this->link_manager = new LinkCentral_Link_Manager();
        add_action( 'rest_api_init', array($this, 'register_rest_fields') );
        add_filter(
            'rest_pre_dispatch',
            array($this, 'check_rest_permission'),
            10,
            3
        );
        // Hook into post creation/update to validate LinkCentral links
        add_filter(
            'rest_pre_insert_linkcentral_link',
            array($this, 'validate_rest_link_data'),
            10,
            2
        );
        // Handle post-creation meta updates
        add_action(
            'rest_after_insert_linkcentral_link',
            array($this, 'save_rest_link_meta'),
            10,
            3
        );
    }

    /**
     * Check permissions for REST API requests
     */
    public function check_rest_permission( $result, $server, $request ) {
        $route = $request->get_route();
        if ( strpos( $route, '/wp/v2/linkcentral_link' ) === 0 ) {
            // Require authentication for all LinkCentral REST API access
            if ( !is_user_logged_in() ) {
                return new WP_Error('rest_forbidden', __( 'Authentication required.', 'linkcentral' ), array(
                    'status' => 401,
                ));
            }
            $method = $request->get_method();
            // Check specific capabilities based on operation
            switch ( $method ) {
                case 'GET':
                    if ( !current_user_can( 'linkcentral_view_links' ) ) {
                        return new WP_Error('rest_forbidden', __( 'You do not have permission to view links.', 'linkcentral' ), array(
                            'status' => 403,
                        ));
                    }
                    break;
                case 'POST':
                    if ( !current_user_can( 'linkcentral_create_edit_links' ) ) {
                        return new WP_Error('rest_forbidden', __( 'You do not have permission to create links.', 'linkcentral' ), array(
                            'status' => 403,
                        ));
                    }
                    break;
                case 'PUT':
                case 'DELETE':
                    if ( !current_user_can( 'linkcentral_create_edit_links' ) ) {
                        return new WP_Error('rest_forbidden', __( 'You do not have permission to modify links.', 'linkcentral' ), array(
                            'status' => 403,
                        ));
                    }
                    break;
            }
        }
        return $result;
    }

    /**
     * Build link_data array for computed attribute callbacks (single source for meta).
     *
     * @param array $object REST post object with 'id'.
     * @return array Link data for LinkCentral_Link_Attributes.
     */
    private function get_link_data_for_computed_attributes( $object ) {
        $id = (int) $object['id'];
        return array(
            'new_tab'                 => ( get_post_meta( $id, '_linkcentral_new_tab', true ) ?: 'default' ),
            'nofollow'                => ( get_post_meta( $id, '_linkcentral_nofollow', true ) ?: 'default' ),
            'sponsored'               => ( get_post_meta( $id, '_linkcentral_sponsored', true ) ?: 'default' ),
            'destination_url'         => get_post_meta( $id, '_linkcentral_destination_url', true ),
            'css_classes_option'      => ( get_post_meta( $id, '_linkcentral_css_classes_option', true ) ?: 'default' ),
            'custom_css_classes'      => get_post_meta( $id, '_linkcentral_custom_css_classes', true ),
            'other_attributes_option' => ( get_post_meta( $id, '_linkcentral_other_attributes_option', true ) ?: 'default' ),
            'custom_other_attributes' => get_post_meta( $id, '_linkcentral_custom_other_attributes', true ),
        );
    }

    /**
     * Register custom REST API fields for the link post type
     */
    public function register_rest_fields() {
        // Batch get callback for efficiency - fetches all meta in one query per post
        $get_meta_callback = function ( $object, $field_name ) {
            // Get all meta for this post in one efficient query
            $all_meta = get_post_meta( $object['id'] );
            $meta_key = '_linkcentral_' . $field_name;
            // Return the single value for this field
            return $all_meta[$meta_key][0] ?? null;
        };
        // Link fields with batch retrieval
        $link_fields = array(
            'slug'                    => array(
                'description' => __( 'Slug for the link with prefix', 'linkcentral' ),
                'type'        => 'string',
                'required'    => true,
                'pattern'     => '^[a-zA-Z0-9\\-_]+$',
                'maxLength'   => 200,
            ),
            'destination_url'         => array(
                'description' => __( 'Destination URL for the link', 'linkcentral' ),
                'type'        => 'string',
                'format'      => 'uri',
                'required'    => true,
                'maxLength'   => 2048,
            ),
            'new_tab'                 => array(
                'description' => __( 'Open in new tab setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'yes', 'no'),
                'default'     => 'default',
            ),
            'nofollow'                => array(
                'description' => __( 'Nofollow setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'yes', 'no'),
                'default'     => 'default',
            ),
            'sponsored'               => array(
                'description' => __( 'Sponsored setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'yes', 'no'),
                'default'     => 'default',
            ),
            'redirection_type'        => array(
                'description' => __( 'Redirection type for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array(
                    'default',
                    '307',
                    '302',
                    '301'
                ),
                'default'     => 'default',
            ),
            'note'                    => array(
                'description' => __( 'Administrative note for the link', 'linkcentral' ),
                'type'        => 'string',
                'maxLength'   => 1000,
            ),
            'parameter_forwarding'    => array(
                'description' => __( 'Parameter forwarding setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'yes', 'no'),
                'default'     => 'default',
            ),
            'css_classes_option'      => array(
                'description' => __( 'CSS classes setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'replace', 'append'),
                'default'     => 'default',
            ),
            'custom_css_classes'      => array(
                'description' => __( 'Custom CSS classes for the link', 'linkcentral' ),
                'type'        => 'string',
                'maxLength'   => 255,
                'pattern'     => '^[a-zA-Z0-9\\s\\-_]+$',
            ),
            'other_attributes_option' => array(
                'description' => __( 'Other attributes setting for the link', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('default', 'replace', 'append'),
                'default'     => 'default',
            ),
            'custom_other_attributes' => array(
                'description' => __( 'Custom other attributes for the link', 'linkcentral' ),
                'type'        => 'string',
                'maxLength'   => 255,
                'pattern'     => '^[a-zA-Z0-9\\s\\-_]+$',
            ),
            'disable_slug_prefix'     => array(
                'description' => __( 'Whether slug prefix is disabled for the link', 'linkcentral' ),
                'type'        => 'boolean',
                'default'     => false,
            ),
        );
        foreach ( $link_fields as $field_name => $schema ) {
            register_rest_field( 'linkcentral_link', $field_name, array(
                'get_callback' => function ( $object ) use($get_meta_callback, $field_name) {
                    // Special handling for slug field to return path with prefix
                    if ( $field_name === 'slug' ) {
                        $disable_slug_prefix = get_post_meta( $object['id'], '_linkcentral_disable_slug_prefix', true );
                        $sanitized_slug = linkcentral_sanitize_output_slug( $object['slug'] );
                        if ( $disable_slug_prefix ) {
                            return '/' . $sanitized_slug;
                        } else {
                            $url_prefix = get_option( 'linkcentral_url_prefix', 'go' );
                            return '/' . $url_prefix . '/' . $sanitized_slug;
                        }
                    }
                    // Default meta callback for other fields
                    return $get_meta_callback( $object, $field_name );
                },
                'schema'       => $schema,
            ) );
        }
        // Special fields
        register_rest_field( 'linkcentral_link', 'url', array(
            'get_callback' => function ( $object ) {
                $post = get_post( $object['id'] );
                return linkcentral_get_link_url( $object['id'], $post->post_name );
            },
            'schema'       => array(
                'description' => __( 'Complete URL for the link', 'linkcentral' ),
                'type'        => 'string',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'global_new_tab', array(
            'get_callback' => function ( $object ) {
                return get_option( 'linkcentral_global_new_tab', false );
            },
            'schema'       => array(
                'description' => __( 'Global open in new tab setting', 'linkcentral' ),
                'type'        => 'boolean',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'global_nofollow', array(
            'get_callback' => function ( $object ) {
                return get_option( 'linkcentral_global_nofollow', false );
            },
            'schema'       => array(
                'description' => __( 'Global nofollow setting', 'linkcentral' ),
                'type'        => 'boolean',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'global_sponsored', array(
            'get_callback' => function ( $object ) {
                return get_option( 'linkcentral_global_sponsored', false );
            },
            'schema'       => array(
                'description' => __( 'Global sponsored setting', 'linkcentral' ),
                'type'        => 'boolean',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'global_other_attributes', array(
            'get_callback' => function ( $object ) {
                return get_option( 'linkcentral_custom_other_attributes', '' );
            },
            'schema'       => array(
                'description' => __( 'Global other attributes', 'linkcentral' ),
                'type'        => 'string',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'global_css_classes', array(
            'get_callback' => function ( $object ) {
                return get_option( 'linkcentral_custom_css_classes', '' );
            },
            'schema'       => array(
                'description' => __( 'Global CSS classes', 'linkcentral' ),
                'type'        => 'string',
            ),
        ) );
        // Effective (final applied) values - single source of truth for editors; names avoid confusion with stored options (nofollow, css_classes_option, etc.)
        register_rest_field( 'linkcentral_link', 'effective_rel_nofollow', array(
            'get_callback' => function ( $object ) {
                $link_data = $this->get_link_data_for_computed_attributes( $object );
                $attrs = new LinkCentral_Link_Attributes();
                return $attrs->get_nofollow_from_data( $link_data );
            },
            'schema'       => array(
                'description' => __( 'Effective nofollow rel value for output (respects global scope)', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('', 'nofollow'),
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'effective_rel_sponsored', array(
            'get_callback' => function ( $object ) {
                $link_data = $this->get_link_data_for_computed_attributes( $object );
                $attrs = new LinkCentral_Link_Attributes();
                return $attrs->get_sponsored_from_data( $link_data );
            },
            'schema'       => array(
                'description' => __( 'Effective sponsored rel value for output (respects global scope)', 'linkcentral' ),
                'type'        => 'string',
                'enum'        => array('', 'sponsored'),
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'effective_rel_other_attributes', array(
            'get_callback' => function ( $object ) {
                $link_data = $this->get_link_data_for_computed_attributes( $object );
                $attrs = new LinkCentral_Link_Attributes();
                return $attrs->get_other_attributes_from_data( $link_data );
            },
            'schema'       => array(
                'description' => __( 'Effective other rel attributes for output (replace/append/default)', 'linkcentral' ),
                'type'        => 'string',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'effective_new_tab', array(
            'get_callback' => function ( $object ) {
                $link_data = $this->get_link_data_for_computed_attributes( $object );
                $attrs = new LinkCentral_Link_Attributes();
                return $attrs->get_new_tab_from_data( $link_data );
            },
            'schema'       => array(
                'description' => __( 'Effective open in new tab value', 'linkcentral' ),
                'type'        => 'boolean',
            ),
        ) );
        register_rest_field( 'linkcentral_link', 'effective_css_classes', array(
            'get_callback' => function ( $object ) {
                $link_data = $this->get_link_data_for_computed_attributes( $object );
                $attrs = new LinkCentral_Link_Attributes();
                return $attrs->get_css_classes_from_data( $link_data );
            },
            'schema'       => array(
                'description' => __( 'Effective CSS classes for output (replace/append/default)', 'linkcentral' ),
                'type'        => 'string',
            ),
        ) );
    }

    /**
     * Save LinkCentral meta fields after successful post creation/update
     *
     * @param WP_Post $post The post object
     * @param WP_REST_Request $request The request object
     * @param bool $creating Whether this is a create operation
     */
    public function save_rest_link_meta( $post, $request, $creating ) {
        // Get all the custom field data from the request
        $params = $request->get_params();
        // Prepare data for Link Manager
        $link_data = [
            'title' => $post->post_title,
            'slug'  => $post->post_name,
        ];
        // Add custom fields from request (same structure as validation)
        $all_fields = [
            'title',
            'slug',
            'destination_url',
            'new_tab',
            'nofollow',
            'sponsored',
            'redirection_type',
            'note',
            'parameter_forwarding',
            'css_classes_option',
            'custom_css_classes',
            'other_attributes_option',
            'custom_other_attributes',
            'disable_slug_prefix',
            'dynamic_rules',
            'keywords'
        ];
        foreach ( $all_fields as $field ) {
            if ( isset( $params[$field] ) ) {
                $link_data[$field] = $params[$field];
            }
        }
        // Use Link Manager to save meta data (validation already happened in pre_insert hook)
        $this->link_manager->save_link_meta( $post->ID, $this->link_manager->sanitize_link_data( $link_data ) );
    }

    /**
     * Validate LinkCentral link data before REST API post creation/update
     *
     * @param stdClass|WP_Error $prepared_post Post object or WP_Error
     * @param WP_REST_Request $request Request object
     * @return stdClass|WP_Error Post object on success, WP_Error on validation failure
     */
    public function validate_rest_link_data( $prepared_post, $request ) {
        // If already an error, return it
        if ( is_wp_error( $prepared_post ) ) {
            return $prepared_post;
        }
        // Get the request parameters
        $params = $request->get_params();
        // Reject 'pending' status for LinkCentral links
        if ( isset( $params['status'] ) && $params['status'] === 'pending' ) {
            return new WP_Error('rest_invalid_status', __( 'LinkCentral links do not support pending status.', 'linkcentral' ), array(
                'status' => 400,
            ));
        }
        // Define required fields for new links (must be provided in request)
        $required_fields = ['title', 'slug', 'destination_url'];
        // Define all possible fields
        $all_fields = array_merge( $required_fields, [
            'new_tab',
            'nofollow',
            'sponsored',
            'redirection_type',
            'note',
            'parameter_forwarding',
            'css_classes_option',
            'custom_css_classes',
            'other_attributes_option',
            'custom_other_attributes',
            'disable_slug_prefix',
            'dynamic_rules',
            'keywords'
        ] );
        // Process only fields that are actually provided in the request
        $link_data = [];
        foreach ( $all_fields as $field ) {
            if ( isset( $params[$field] ) ) {
                $link_data[$field] = $params[$field];
            }
        }
        // Get post ID for updates (0 for new posts)
        $post_id = ( isset( $prepared_post->ID ) ? $prepared_post->ID : 0 );
        // Validate using Link Manager
        $validation_result = $this->link_manager->validate_link_data( $link_data, 'rest_api', $post_id );
        if ( is_wp_error( $validation_result ) ) {
            // Return the validation error - this will prevent post creation
            return $validation_result;
        }
        // If validation passes, return the prepared post
        return $prepared_post;
    }

    /**
     * Get keywords callback for REST API
     *
     * @param array $object Post object
     * @return array Keywords data
     */
    public function get_keywords_callback( $object ) {
        global $wpdb;
        $keywords = $wpdb->get_results( $wpdb->prepare( "SELECT keyword, density FROM {$wpdb->prefix}linkcentral_keywords WHERE link_id = %d ORDER BY id ASC", $object['id'] ) );
        $result = [];
        foreach ( $keywords as $keyword ) {
            $result[] = [
                'keyword' => $keyword->keyword,
                'density' => $keyword->density,
            ];
        }
        return $result;
    }

    /**
     * Get dynamic rules callback for REST API
     *
     * @param array $object Post object
     * @return array Dynamic rules data
     */
    public function get_dynamic_rules_callback( $object ) {
        $rules = get_post_meta( $object['id'], '_linkcentral_dynamic_rules', true );
        return ( is_array( $rules ) ? $rules : [] );
    }

}
