<?php

namespace FleekDash\Controllers\Post;

use FleekDash\Core\AuthMiddleware;
use FleekDash\Libs\API\ResponseService;

/**
 * Handles post duplication logic extracted from PostController.
 *
 * @package FleekDash\Controllers\Post
 */
class PostDuplicateHandler
{
    private const MSG_NOT_FOUND = 'Post not found';

    /**
     * Execute post duplication. Returns REST response.
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     * @phpcs:ignore SonarQube.S1142 -- Duplication flow requires early returns for validation and wp_error
     */
    public static function execute(\WP_REST_Request $request): \WP_REST_Response
    {
        global $wpdb;

        $auth_result = AuthMiddleware::check('authenticated');
        $source_id = (int) $request->get_param('source_id');
        $post_type = $request->get_param('post_type');
        $source = \get_post($source_id);

        $error = self::validateRequest($auth_result, $source, $post_type);
        if ($error !== null) {
            return $error;
        }

        $new_post_type = \post_type_exists($post_type) ? $post_type : $source->post_type;
        $preserve_schedule = filter_var(
            $request->get_param('preserve_schedule'),
            FILTER_VALIDATE_BOOLEAN
        );
        $raw_content = $wpdb->get_var($wpdb->prepare(
            "SELECT post_content FROM {$wpdb->posts} WHERE ID = %d",
            $source_id
        ));
        $raw_excerpt = $wpdb->get_var($wpdb->prepare(
            "SELECT post_excerpt FROM {$wpdb->posts} WHERE ID = %d",
            $source_id
        ));

        $error = null;
        if ($raw_content === null) {
            $error = ResponseService::error(self::MSG_NOT_FOUND, null, 404);
        } else {
            $title = $source->post_title !== '' ? $source->post_title . ' (Copy)' : __('Copy', 'fleekdash');
            $post_data = [
                'post_title' => $title,
                'post_content' => '',
                'post_excerpt' => '',
                'post_status' => 'draft',
                'post_type' => $new_post_type,
                'post_author' => $source->post_author,
                'post_parent' => (int) $source->post_parent,
                'post_name' => '',
                'comment_status' => $source->comment_status,
                'ping_status' => $source->ping_status,
            ];

            if ($preserve_schedule) {
                $post_data['post_date'] = $source->post_date;
                $post_data['post_date_gmt'] = $source->post_date_gmt;
            }

            $new_id = \wp_insert_post($post_data, true);
            if (is_wp_error($new_id)) {
                $error = ResponseService::error('Failed to create duplicate: ' . $new_id->get_error_message(), null, 400);
            } else {
                $wpdb->update(
                $wpdb->posts,
                ['post_content' => $raw_content, 'post_excerpt' => (string) $raw_excerpt],
                ['ID' => $new_id],
                ['%s', '%s'],
                ['%d']
            );

            \clean_post_cache($new_id);
            self::copyTaxonomies($source_id, $new_id, $source->post_type);
            self::copyMeta($source_id, $new_id);

            $post = \get_post($new_id);
            return ResponseService::success(PostFormatter::formatPostForGrid($post), 'Post duplicated successfully', 201);
            }
        }

        return $error;
    }

    /**
     * @param \WP_Post|null $source From {@see \get_post()}.
     */
    private static function validateRequest(array $auth_result, ?\WP_Post $source, ?string $post_type): ?\WP_REST_Response
    {
        $error = null;
        if (!$source || in_array($source->post_type, ['revision', 'nav_menu_item', 'auto-draft'], true)) {
            $error = ResponseService::error(self::MSG_NOT_FOUND . ' or cannot be duplicated', null, 404);
        } elseif ($auth_result['authenticated'] && !\current_user_can("edit_{$source->post_type}s") && !\current_user_can('manage_options')) {
            $error = ResponseService::error("You don't have permission to duplicate this post type", null, 403);
        } else {
            $new_post_type = \post_type_exists($post_type) ? $post_type : $source->post_type;
            if ($auth_result['authenticated'] && !\current_user_can("edit_{$new_post_type}s") && !\current_user_can('manage_options')) {
                $error = ResponseService::error("You don't have permission to create this post type", null, 403);
            }
        }
        return $error;
    }

    private static function copyTaxonomies(int $source_id, int $new_id, string $post_type): void
    {
        $taxonomies = get_object_taxonomies($post_type);
        foreach ($taxonomies as $taxonomy) {
            $terms = wp_get_post_terms($source_id, $taxonomy);
            if (!empty($terms) && !is_wp_error($terms)) {
                $term_ids = array_map(static fn ($t) => $t->term_id, $terms);
                wp_set_object_terms($new_id, $term_ids, $taxonomy);
            }
        }
    }

    private static function copyMeta(int $source_id, int $new_id): void
    {
        $meta = \get_post_meta($source_id);
        if (empty($meta)) {
            return;
        }
        foreach ($meta as $meta_key => $values) {
            $value = is_array($values) && count($values) === 1 ? $values[0] : $values;
            \update_post_meta($new_id, $meta_key, $value);
        }
    }
}
