<?php
/**
 * Titles & Meta Bulk Edit REST Controller
 *
 * Provides bulk edit data for SEO titles, descriptions, and focus keywords.
 *
 * @package ProRank\SEO\Core\RestApi
 * @since   1.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\RestApi;

defined( 'ABSPATH' ) || exit;

use ProRank\SEO\Core\FocusKeywords;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * TitlesMetaBulkController class
 */
class TitlesMetaBulkController extends BaseController {
    /**
     * Constructor
     */
    public function __construct() {
        $this->rest_base = 'titles-meta';
    }

    /**
     * Register routes.
     *
     * @return void
     */
    public function register_routes(): void {
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/bulk-edit',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_bulk_edit_data'],
                    'permission_callback' => [$this, 'check_permission_edit_posts'],
                    'args'                => [
                        'post_type' => [
                            'description' => __('Post type', 'prorank-seo'),
                            'type'        => 'string',
                            'default'     => 'post',
                        ],
                        'paged'     => [
                            'description' => __('Page number', 'prorank-seo'),
                            'type'        => 'integer',
                            'default'     => 1,
                            'minimum'     => 1,
                        ],
                        'per_page'  => [
                            'description' => __('Posts per page', 'prorank-seo'),
                            'type'        => 'integer',
                            'default'     => 20,
                            'minimum'     => 1,
                            'maximum'     => 100,
                        ],
                        'search'    => [
                            'description' => __('Search term', 'prorank-seo'),
                            'type'        => 'string',
                            'default'     => '',
                        ],
                    ],
                ],
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'save_bulk_edit_data'],
                    'permission_callback' => [$this, 'check_permission_edit_posts'],
                ],
            ]
        );
    }

    /**
     * Get bulk edit data.
     *
     * @param WP_REST_Request $request Request object.
     * @return WP_REST_Response
     */
    public function get_bulk_edit_data(WP_REST_Request $request): WP_REST_Response {
        return $this->try_callback(function() use ($request): WP_REST_Response {
            $post_type = sanitize_key((string) ($request->get_param('post_type') ?: 'post'));
            $paged = max(1, (int) $request->get_param('paged'));
            $per_page = max(1, (int) $request->get_param('per_page'));
            $search = sanitize_text_field((string) $request->get_param('search'));
            $selected_post_ids = $request->get_param('post_ids');

            if (is_string($selected_post_ids)) {
                $selected_post_ids = array_filter(array_map('intval', explode(',', $selected_post_ids)));
            } elseif (is_array($selected_post_ids)) {
                $selected_post_ids = array_filter(array_map('intval', $selected_post_ids));
            } else {
                $selected_post_ids = [];
            }

            $args = [
                'post_type'      => $post_type,
                'posts_per_page' => $per_page,
                'paged'          => $paged,
                'post_status'    => 'any',
                'orderby'        => 'date',
                'order'          => 'DESC',
            ];

            if ($search !== '') {
                $args['s'] = $search;
            }

            if (!empty($selected_post_ids)) {
                $args['post__in'] = $selected_post_ids;
                $args['orderby'] = 'post__in';
                $args['posts_per_page'] = max(count($selected_post_ids), $per_page);
                $args['paged'] = 1;
            }

            $query = new \WP_Query($args);
            $posts_data = [];

            foreach ($query->posts as $post) {
                $post_id = (int) $post->ID;
                if (!current_user_can('edit_post', $post_id)) {
                    continue;
                }

                $seo_title = $this->get_meta_with_fallback($post_id, '_prorank_seo_title', [
                    '_prorank_meta_title',
                    '_prorank_title',
                ]);
                $seo_description = $this->get_meta_with_fallback($post_id, '_prorank_seo_description', [
                    '_prorank_meta_description',
                    '_prorank_description',
                ]);

                $focus_keywords = FocusKeywords::get($post_id);
                $focus_keyword  = FocusKeywords::get_primary($post_id);

                $posts_data[] = [
                    'id'              => $post_id,
                    'title'           => get_the_title($post_id),
                    'url'             => get_permalink($post_id),
                    'excerpt'         => get_the_excerpt($post_id),
                    'seo_title'       => $seo_title,
                    'seo_description' => $seo_description,
                    'focus_keyword'   => $focus_keyword,
                    'focus_keywords'  => $focus_keywords,
                ];
            }

            return $this->get_success_response([
                'posts'        => $posts_data,
                'total'        => $query->found_posts,
                'pages'        => $query->max_num_pages,
                'current_page' => $paged,
                'selected_post_ids' => $selected_post_ids,
            ]);
        });
    }

    /**
     * Save bulk edit data.
     *
     * @param WP_REST_Request $request Request object.
     * @return WP_REST_Response|\WP_Error
     */
    public function save_bulk_edit_data(WP_REST_Request $request) {
        return $this->try_callback(function() use ($request) {
            $updates = $request->get_param('updates');

            if (!is_array($updates) || empty($updates)) {
                return $this->get_error_response(
                    __('Invalid bulk edit data', 'prorank-seo'),
                    400,
                    'invalid_data'
                );
            }

            $updated_count = 0;
            $errors = [];

            foreach ($updates as $update) {
                if (empty($update['id'])) {
                    continue;
                }

                $post_id = absint($update['id']);
                if (!get_post($post_id)) {
                    $errors[] = sprintf(
                        /* translators: %d: post ID */
                        __('Post ID %d not found', 'prorank-seo'),
                        $post_id
                    );
                    continue;
                }

                if (!current_user_can('edit_post', $post_id)) {
                    $errors[] = sprintf(
                        /* translators: %d: post ID */
                        __('Insufficient permissions for post ID %d', 'prorank-seo'),
                        $post_id
                    );
                    continue;
                }

                if (array_key_exists('seo_title', $update)) {
                    update_post_meta($post_id, '_prorank_seo_title', sanitize_text_field((string) $update['seo_title']));
                }

                if (array_key_exists('seo_description', $update)) {
                    update_post_meta($post_id, '_prorank_seo_description', sanitize_textarea_field((string) $update['seo_description']));
                }

                if (array_key_exists('focus_keywords', $update)) {
                    FocusKeywords::save($post_id, $update['focus_keywords']);
                } elseif (array_key_exists('focus_keyword', $update)) {
                    $keyword = sanitize_text_field((string) $update['focus_keyword']);
                    if ($keyword !== '') {
                        $existing  = FocusKeywords::get($post_id);
                        $secondary = array_filter($existing, function ($kw) { return empty($kw['primary']); });
                        $input     = array_merge([['keyword' => $keyword, 'primary' => true]], array_values($secondary));
                    } else {
                        $input = [];
                    }
                    FocusKeywords::save($post_id, $input);
                }

                $updated_count++;
            }

            return $this->get_success_response(
                [
                    'updated' => $updated_count,
                    'errors'  => $errors,
                ],
                sprintf(
                    /* translators: %d: number of items updated */
                    __('Updated %d items', 'prorank-seo'),
                    $updated_count
                )
            );
        });
    }

    /**
     * Read a meta value with fallback keys for legacy data.
     *
     * @param int    $post_id   Post ID.
     * @param string $primary   Primary meta key.
     * @param array  $fallbacks Fallback meta keys.
     * @return string
     */
    private function get_meta_with_fallback(int $post_id, string $primary, array $fallbacks): string {
        $value = get_post_meta($post_id, $primary, true);
        if (!empty($value)) {
            return (string) $value;
        }

        foreach ($fallbacks as $key) {
            $fallback = get_post_meta($post_id, $key, true);
            if (!empty($fallback)) {
                return (string) $fallback;
            }
        }

        return '';
    }
}
