<?php
/**
 * Author: Rymera Web Co.
 *
 * @package SAAI\REST
 */

namespace SAAI\REST;

use SAAI\Abstracts\Abstract_REST;
use SAAI\Classes\Notification;
use SAAI\Traits\Singleton_Trait;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Notifications REST API controller class.
 *
 * @since 1.0.0
 */
class Notifications extends Abstract_REST {

    use Singleton_Trait;

    /**
     * Holds the class instance object
     *
     * @since 1.0.0
     * @var Notifications $instance object
     */
    protected static $instance;

    /**
     * REST constructor.
     *
     * @since 1.0.0
     */
    public function __construct() {
    }

    /**
     * Works as constructor for this class.
     *
     * @since 1.0.0
     * @return void
     */
    public function register_plugin_routes() {
        $this->rest_base = 'notifications';
        parent::register_plugin_routes();
    }

    /**
     * Register the routes for notifications.
     *
     * @since 1.0.0
     * @return void
     */
    public function register_routes() {
        // Get all notifications with pagination and filtering.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base",
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'get_notifications' ),
                'permission_callback' => array( $this, 'get_items_permissions_check' ),
                'args'                => array(
                    'page'         => array(
                        'type'              => 'integer',
                        'default'           => 1,
                        'sanitize_callback' => 'absint',
                    ),
                    'per_page'     => array(
                        'type'              => 'integer',
                        'default'           => 10,
                        'sanitize_callback' => 'absint',
                    ),
                    'archived'     => array(
                        'type'    => 'boolean',
                        'default' => false,
                    ),
                    'hide_archive' => array(
                        'type'    => 'boolean',
                        'default' => false,
                    ),
                    'agent'        => array(
                        'type'              => 'string',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'product_id'   => array(
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ),
                    'date_after'   => array(
                        'type'              => 'string',
                        'description'       => __( 'Filter notifications created or updated after this date (ISO 8601 format).', 'storeagent-ai-for-woocommerce' ),
                        'validate_callback' => function ( $param ) {
                            return strtotime( $param ) !== false;
                        },
                    ),
                    'date_before'  => array(
                        'type'              => 'string',
                        'description'       => __( 'Filter notifications created or updated before this date (ISO 8601 format).', 'storeagent-ai-for-woocommerce' ),
                        'validate_callback' => function ( $param ) {
                            return strtotime( $param ) !== false;
                        },
                    ),
                    'date_field'   => array(
                        'type'        => 'string',
                        'default'     => 'created_at',
                        'enum'        => array( 'created_at', 'updated_at' ),
                        'description' => __( 'Which date field to filter by.', 'storeagent-ai-for-woocommerce' ),
                    ),
                    'status'       => array(
                        'type'        => 'array',
                        'description' => __( 'Filter notifications by status.', 'storeagent-ai-for-woocommerce' ),
                        'items'       => array(
                            'type' => 'string',
                            'enum' => array( 'pending', 'accepted', 'rejected', 'archived' ),
                        ),
                    ),
                ),
            )
        );

        // Get a single notification by ID.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)",
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'get_notification' ),
                'permission_callback' => array( $this, 'get_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Archive a notification.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)/archive",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'archive_notification' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Unarchive a notification.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)/unarchive",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'unarchive_notification' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Accept a notification.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)/accept",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'accept_notification' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Reject a notification.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)/reject",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'reject_notification' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Handle expand description action.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<id>[\d]+)/expand_description",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'expand_description' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'id' => array(
                        'required'          => true,
                        'validate_callback' => function ( $param ) {
                            return is_numeric( $param );
                        },
                    ),
                ),
            )
        );

        // Register the schema.
        $this->schema = array(
            '$schema'    => 'http://json-schema.org/draft-04/schema#',
            'title'      => 'notification',
            'type'       => 'object',
            'properties' => array(
                'id'         => array(
                    'description' => __( 'Unique identifier for the notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'integer',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'type'       => array(
                    'description' => __( 'Type of notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'enum'        => array( 'info', 'warning', 'success', 'decision' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'title'      => array(
                    'description' => __( 'The notification title.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                ),
                'message'    => array(
                    'description' => __( 'The notification message.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                ),
                'agent'      => array(
                    'description' => __( 'The agent that created the notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                ),
                'product_id' => array(
                    'description' => __( 'The ID of the product related to the notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'integer',
                    'context'     => array( 'view', 'edit' ),
                ),
                'product'    => array(
                    'description' => __( 'The product data related to the notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'object',
                    'context'     => array( 'view', 'edit' ),
                    'properties'  => array(
                        'id'    => array(
                            'description' => __( 'Product ID.', 'storeagent-ai-for-woocommerce' ),
                            'type'        => 'integer',
                            'context'     => array( 'view', 'edit' ),
                        ),
                        'title' => array(
                            'description' => __( 'Product title.', 'storeagent-ai-for-woocommerce' ),
                            'type'        => 'string',
                            'context'     => array( 'view', 'edit' ),
                        ),
                        'url'   => array(
                            'description' => __( 'Product edit URL.', 'storeagent-ai-for-woocommerce' ),
                            'type'        => 'string',
                            'context'     => array( 'view', 'edit' ),
                        ),
                    ),
                ),
                'status'     => array(
                    'description' => __( 'The notification status.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'enum'        => array( 'pending', 'accepted', 'rejected', 'archived' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'archived'   => array(
                    'description' => __( 'Whether the notification is archived.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'boolean',
                    'context'     => array( 'view', 'edit' ),
                ),
                'is_read'    => array(
                    'description' => __( 'Whether the notification has been read.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'boolean',
                    'context'     => array( 'view', 'edit' ),
                ),
                'created_at' => array(
                    'description' => __( 'The date the notification was created.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'format'      => 'date-time',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'updated_at' => array(
                    'description' => __( 'The date the notification was last updated.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'string',
                    'format'      => 'date-time',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'actions'    => array(
                    'description' => __( 'The available actions for this notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'array',
                    'context'     => array( 'view', 'edit' ),
                    'items'       => array(
                        'type'       => 'object',
                        'properties' => array(
                            'label'    => array(
                                'description' => __( 'Action label.', 'storeagent-ai-for-woocommerce' ),
                                'type'        => 'string',
                            ),
                            'action'   => array(
                                'description' => __( 'Action identifier.', 'storeagent-ai-for-woocommerce' ),
                                'type'        => 'string',
                            ),
                            'endpoint' => array(
                                'description' => __( 'API endpoint for the action.', 'storeagent-ai-for-woocommerce' ),
                                'type'        => 'string',
                            ),
                            'callback' => array(
                                'description' => __( 'Callback to execute.', 'storeagent-ai-for-woocommerce' ),
                                'type'        => 'object',
                            ),
                        ),
                    ),
                ),
                'extra'      => array(
                    'description' => __( 'Extra data for the notification.', 'storeagent-ai-for-woocommerce' ),
                    'type'        => 'object',
                    'context'     => array( 'view', 'edit' ),
                ),
            ),
        );

        // Add filter for extending the schema.
        $this->schema = apply_filters( 'saai_notification_rest_schema', $this->schema );
    }

    /**
     * Get paginated list of notifications
     *
     * Gets a list of notifications with pagination support.
     * The 'archived' parameter can filter notifications by archived status.
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response The response object.
     */
    public function get_notifications( $request ) {
        $page        = $request->get_param( 'page' );
        $per_page    = $request->get_param( 'per_page' );
        $archived    = $request->get_param( 'archived' );
        $agent       = $request->get_param( 'agent' );
        $product_id  = $request->get_param( 'product_id' );
        $date_after  = $request->get_param( 'date_after' );
        $date_before = $request->get_param( 'date_before' );
        $date_field  = $request->get_param( 'date_field' );
        $status      = $request->get_param( 'status' );

        $args = array(
            'page'        => $page,
            'per_page'    => $per_page,
            'archived'    => $archived,
            'agent'       => $agent,
            'product_id'  => $product_id,
            'date_after'  => $date_after,
            'date_before' => $date_before,
            'date_field'  => $date_field,
        );

        // Add status filtering if provided.
        if ( ! empty( $status ) && is_array( $status ) ) {
            $args['status'] = $status;
        }

        $notifications = Notification::instance()->get_all( $args );

        // Count with all filter parameters, except pagination.
        $count_args = array(
            'archived'    => $archived,
            'agent'       => $agent,
            'product_id'  => $product_id,
            'date_after'  => $date_after,
            'date_before' => $date_before,
            'date_field'  => $date_field,
        );

        // Apply the same status filter to the count query.
        if ( ! empty( $status ) && is_array( $status ) ) {
            $count_args['status'] = $status;
        }

        $total_items = Notification::instance()->count_all( $count_args );
        $total_pages = ceil( $total_items / $per_page );

        // Format each notification.
        $data = array();
        foreach ( $notifications as $notification ) {
            $data[] = $this->prepare_notification_response( $notification );
        }

        $response = rest_ensure_response( $data );
        $response->header( 'X-WP-Total', $total_items );
        $response->header( 'X-WP-TotalPages', $total_pages );

        return $response;
    }

    /**
     * Get a single notification
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_notification( $request ) {
        $id = $request->get_param( 'id' );

        $notification = Notification::instance()->get( $id );

        if ( ! $notification ) {
            return new WP_Error(
                'notification_not_found',
                __( 'Notification not found.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        // Mark notification as read.
        Notification::instance()->mark_as_read( $id );

        return rest_ensure_response( $this->prepare_notification_response( $notification ) );
    }

    /**
     * Archive a notification
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function archive_notification( $request ) {
        $id = $request->get_param( 'id' );

        do_action( 'saai_before_notification_archive', $id );

        $result = Notification::instance()->archive( $id );

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

        do_action( 'saai_after_notification_archive', $id );

        return rest_ensure_response(
            array(
                'success' => true,
                'message' => __( 'Notification archived successfully.', 'storeagent-ai-for-woocommerce' ),
            )
        );
    }

    /**
     * Unarchive a notification
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function unarchive_notification( $request ) {
        $id = $request->get_param( 'id' );

        do_action( 'saai_before_notification_unarchive', $id );

        $result = Notification::instance()->unarchive( $id );

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

        do_action( 'saai_after_notification_unarchive', $id );

        return rest_ensure_response(
            array(
                'success' => true,
                'message' => __( 'Notification unarchived successfully.', 'storeagent-ai-for-woocommerce' ),
            )
        );
    }

    /**
     * Accept a notification and execute its callback
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function accept_notification( $request ) {
        $id = $request->get_param( 'id' );

        do_action( 'saai_before_notification_accept', $id );

        // Get the notification to check for product information.
        $notification = Notification::instance()->get( $id );

        if ( ! $notification ) {
            return new WP_Error(
                'notification_not_found',
                __( 'Notification not found.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        // Ensure we're only acting on a single notification by ID.
        $result = Notification::instance()->accept( $id );

        if ( is_wp_error( $result ) ) {
            // Check for specific error codes to provide better user feedback.
            if ( 'already_accepted' === $result->get_error_code() ) {
                return rest_ensure_response(
                    array(
                        'success' => true,
                        'message' => __( 'This notification has already been accepted and processed.', 'storeagent-ai-for-woocommerce' ),
                    )
                );
            } elseif ( 'invalid_status' === $result->get_error_code() ) {
                return rest_ensure_response(
                    array(
                        'success' => false,
                        'message' => __( 'This notification cannot be accepted because it is not in a pending state.', 'storeagent-ai-for-woocommerce' ),
                    )
                );
            }
            return $result;
        }

        do_action( 'saai_after_notification_accept', $id, $result );

        $response_data = array(
            'success' => true,
            'message' => __( 'Notification accepted and actions performed successfully.', 'storeagent-ai-for-woocommerce' ),
            'data'    => $result,
        );

        // Add product information if available.
        if ( ! empty( $notification->product_id ) ) {
            $product_data = $this->get_product_data( $notification->product_id );
            if ( $product_data ) {
                $response_data['product'] = $product_data;
            }
        }

        return rest_ensure_response( $response_data );
    }

    /**
     * Reject a notification and execute its callback
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function reject_notification( $request ) {
        $id = $request->get_param( 'id' );

        do_action( 'saai_before_notification_reject', $id );

        $result = Notification::instance()->reject( $id );

        if ( is_wp_error( $result ) ) {
            // Check for specific error codes to provide better user feedback.
            if ( 'already_rejected' === $result->get_error_code() ) {
                return rest_ensure_response(
                    array(
                        'success' => true,
                        'message' => __( 'This notification has already been rejected.', 'storeagent-ai-for-woocommerce' ),
                    )
                );
            } elseif ( 'invalid_status' === $result->get_error_code() ) {
                return rest_ensure_response(
                    array(
                        'success' => false,
                        'message' => __( 'This notification cannot be rejected because it is not in a pending state.', 'storeagent-ai-for-woocommerce' ),
                    )
                );
            }
            return $result;
        }

        do_action( 'saai_after_notification_reject', $id, $result );

        return rest_ensure_response(
            array(
                'success' => true,
                'message' => __( 'Notification rejected successfully.', 'storeagent-ai-for-woocommerce' ),
                'data'    => $result,
            )
        );
    }

    /**
     * Handle expand description action from notification
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function expand_description( $request ) {
        $id = $request->get_param( 'id' );

        do_action( 'saai_before_expand_description', $id );

        // Get the notification to get the product ID.
        $notification = Notification::instance()->get( $id );

        if ( ! $notification ) {
            return new WP_Error(
                'notification_not_found',
                __( 'Notification not found.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        // Get the product ID.
        $product_id = $notification->product_id;

        if ( ! $product_id ) {
            return new WP_Error(
                'product_id_not_found',
                __( 'Product ID not found in notification.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 400 )
            );
        }

        // Mark notification as read and update status.
        Notification::instance()->update(
            $id,
            array(
                'is_read' => 1,
                'status'  => Notification::STATUS_ACCEPTED,
            )
        );

        // Generate the edit URL with our auto-trigger parameter.
        $edit_url = add_query_arg(
            array(
                'post'               => $product_id,
                'action'             => 'edit',
                'saai_auto_generate' => 'description',
            ),
            admin_url( 'post.php' )
        );

        do_action( 'saai_after_expand_description', $id, $product_id );

        return rest_ensure_response(
            array(
                'status'   => 'success',
                'message'  => __( 'You will be redirected to expand the product description.', 'storeagent-ai-for-woocommerce' ),
                'redirect' => $edit_url,
            )
        );
    }

    /**
     * Check if current user has permission to get items
     *
     * @param WP_REST_Request $request The request object.
     * @return bool Whether the user has permission.
     */
    public function get_items_permissions_check( $request ) {
        return current_user_can( 'manage_woocommerce' );
    }

    /**
     * Check if current user has permission to get an item
     *
     * @param WP_REST_Request $request The request object.
     * @return bool Whether the user has permission.
     */
    public function get_item_permissions_check( $request ) {
        return current_user_can( 'manage_woocommerce' );
    }

    /**
     * Check if current user has permission to update an item
     *
     * @param WP_REST_Request $request The request object.
     * @return bool Whether the user has permission.
     */
    public function update_item_permissions_check( $request ) {
        return current_user_can( 'manage_woocommerce' );
    }

    /**
     * Format the response for notifications
     *
     * @param object $notification The notification object.
     * @return array Formatted notification data.
     */
    private function prepare_notification_response( $notification ) {
        // Decode JSON fields.
        if ( ! empty( $notification->extra ) ) {
            $extra = json_decode( $notification->extra, true );
        } else {
            $extra = '';
        }
        if ( ! empty( $notification->actions ) ) {
            $actions = json_decode( $notification->actions, true );
        } else {
            $actions = '';
        }

        // Format dates to ISO 8601.
        $created_at = mysql2date( 'c', $notification->created_at, false );
        $updated_at = mysql2date( 'c', $notification->updated_at, false );

        // Process action endpoints to include the actual ID.
        if ( ! empty( $actions ) ) {
            foreach ( $actions as &$action ) {
                if ( isset( $action['endpoint'] ) ) {
                    $action['endpoint'] = str_replace( '{id}', $notification->id, $action['endpoint'] );
                }
            }
        }

        $data = array(
            'id'           => (int) $notification->id,
            'type'         => $notification->type,
            'title'        => $notification->title,
            'message'      => $notification->message,
            'agent'        => $notification->agent,
            'product_id'   => $notification->product_id ? (int) $notification->product_id : null,
            'product'      => $notification->product_id ? $this->get_product_data( $notification->product_id ) : null,
            'status'       => $notification->status,
            'archived'     => (bool) $notification->archived,
            'hide_archive' => (bool) $notification->hide_archive,
            'is_read'      => (bool) $notification->is_read,
            'created_at'   => $created_at,
            'updated_at'   => $updated_at,
            'actions'      => $actions,
            'extra'        => $extra,
        );

        return apply_filters( 'saai_prepare_notification_response', $data, $notification );
    }

    /**
     * Get product data for a notification
     *
     * @param int $product_id The product ID.
     * @return array|null Product data or null if product doesn't exist.
     */
    private function get_product_data( $product_id ) {
        if ( ! function_exists( 'wc_get_product' ) ) {
            return null;
        }

        $product = wc_get_product( $product_id );

        if ( ! $product ) {
            return null;
        }

        return array(
            'id'    => $product->get_id(),
            'title' => $product->get_name(),
            'url'   => get_edit_post_link( $product_id, 'raw' ),
        );
    }
}
