<?php

if (! defined('ABSPATH')) {
    exit;
} final class PufferGo_Translation_REST
{
    public const NAMESPACE = 'puffergo/v1';

    public const BATCH_POST_TYPES = array('page', 'post');

    public const MAX_BATCH_SIZE = 20;

    public const CONTEXT_OPTION = 'puffergo_translation_context';

    public const CONTEXT_INSTRUCTIONS_MAX_LENGTH = 500;

    public static function default_context(): array
    {
        return array('instructions' => '', );
    }

    public function __construct()
    {
        add_action('rest_api_init', array($this, 'register_routes'));
    }

    public function register_routes(): void
    {
        register_rest_route(self::NAMESPACE, '/translation/overview', array('methods' => 'GET', 'callback' => array($this, 'overview'), 'permission_callback' => array($this, 'check_permission'), ));
        register_rest_route(self::NAMESPACE, '/translation/batch-overview', array('methods' => 'GET', 'callback' => array($this, 'batch_overview'), 'permission_callback' => array($this, 'check_permission'), ));
        register_rest_route(self::NAMESPACE, '/translation/page-status', array('methods' => 'GET', 'callback' => array($this, 'page_status'), 'permission_callback' => array($this, 'check_permission'), 'args' => array('postId' => array('required' => true, 'sanitize_callback' => 'absint', ), ), ));
        register_rest_route(self::NAMESPACE, '/translation/translate', array('methods' => 'POST', 'callback' => array($this, 'translate'), 'permission_callback' => array($this, 'check_permission'), 'args' => array('postId' => array('required' => true, 'sanitize_callback' => 'absint', ), 'lang' => array('required' => true, 'sanitize_callback' => 'sanitize_text_field', ), 'publish' => array('required' => false, 'sanitize_callback' => 'rest_sanitize_boolean', ), ), ));
        register_rest_route(self::NAMESPACE, '/translation/ensure-draft', array('methods' => 'POST', 'callback' => array($this, 'ensure_draft'), 'permission_callback' => array($this, 'check_permission'), 'args' => array('postId' => array('required' => true, 'sanitize_callback' => 'absint', ), 'lang' => array('required' => true, 'sanitize_callback' => 'sanitize_text_field', ), ), ));
        register_rest_route(self::NAMESPACE, '/translation/context', array(array('methods' => 'GET', 'callback' => array($this, 'get_context'), 'permission_callback' => array($this, 'check_permission'), ), array('methods' => 'POST', 'callback' => array($this, 'save_context'), 'permission_callback' => array($this, 'check_permission'), 'args' => array('instructions' => array('required' => false, 'sanitize_callback' => 'sanitize_textarea_field', ), ), ), ));
        register_rest_route(self::NAMESPACE, '/translation/translate-menu', array('methods' => 'POST', 'callback' => array($this, 'translate_menu'), 'permission_callback' => array($this, 'check_permission'), 'args' => array('lang' => array('required' => true, 'sanitize_callback' => 'sanitize_text_field', ), ), ));
    }

    public function check_permission(): bool
    {
        return current_user_can('edit_posts');
    }

    public function overview(): WP_REST_Response
    {
        $active = PufferGo_Polylang::is_active();

        if (! $active) {
            return new WP_REST_Response(array('polylangActive' => false, 'defaultLanguage' => null, 'targetLanguages' => array(), 'pages' => array(), 'hasApiKey' => ! empty(get_option('puffergo_api_key', '')), ), 200);
        } $default_slug = PufferGo_Polylang::default_language();
        $languages = PufferGo_Polylang::languages();
        $default_language = null;
        $target_languages = array();

        foreach ($languages as $language) {
            if ($language['slug'] === $default_slug) {
                $default_language = $language;
            } else {
                $target_languages[] = $language;
            }
        }

return new WP_REST_Response(array('polylangActive' => true, 'defaultLanguage' => $default_language, 'targetLanguages' => $target_languages, 'pages' => $this->collect_pages($default_slug, $target_languages), 'hasApiKey' => ! empty(get_option('puffergo_api_key', '')), ), 200);
    }

    private function collect_pages(string $default_slug, array $target_languages): array
    {
        $query_args = array('post_type' => 'page', 'post_status' => array('publish', 'draft', 'pending', 'private'), 'posts_per_page' => -1, 'orderby' => array('menu_order' => 'ASC', 'title' => 'ASC', ), 'no_found_rows' => true, 'suppress_filters' => false, 'meta_query' => array(array('key' => '_puffergo_managed', 'compare' => 'EXISTS', ), ), );

        if ('' !== $default_slug) {
            $query_args['lang'] = $default_slug;
        } $pages = array();

        foreach (get_posts($query_args) as $page) {
            $translations = array();

            foreach ($target_languages as $language) {
                $translations[ $language['slug'] ] = PufferGo_Page_Translator::status_for($page->ID, $language['slug']);
            } $pages[] = array('id' => $page->ID, 'title' => $page->post_title, 'editUrl' => (string) get_edit_post_link($page->ID, 'raw'), 'viewUrl' => (string) get_permalink($page->ID), 'translations' => $translations, );
        }

return $pages;
    }

    public function batch_overview(): WP_REST_Response
    {
        $base = array('polylangActive' => false, 'defaultLanguage' => null, 'targetLanguages' => array(), 'items' => array(), 'hasApiKey' => ! empty(get_option('puffergo_api_key', '')), 'maxBatchSize' => self::MAX_BATCH_SIZE, );

        if (! PufferGo_Polylang::is_active()) {
            return new WP_REST_Response($base, 200);
        } $default_slug = PufferGo_Polylang::default_language();
        $languages = PufferGo_Polylang::languages();
        $target_languages = array();

        foreach ($languages as $language) {
            if ($language['slug'] === $default_slug) {
                $base['defaultLanguage'] = $language;
            } else {
                $target_languages[] = $language;
            }
        } $counts = array();
        $base['polylangActive'] = true;
        $base['targetLanguages'] = $target_languages;
        $base['items'] = $this->collect_items($default_slug, $target_languages, $counts);
        $base['counts'] = $counts;

        return new WP_REST_Response($base, 200);
    }

    private function collect_items(string $default_slug, array $target_languages, array &$counts): array
    {
        $post_types = array_values(array_unique(array_merge(self::BATCH_POST_TYPES, PufferGo_Polylang::TRANSLATABLE_POST_TYPES)));
        $items = array();

        foreach ($post_types as $post_type) {
            if (class_exists('PufferGo_Module_Settings', false) && ! self::module_enabled_for_post_type($post_type)) {
                continue;
            } $base_args = array('post_type' => $post_type, 'posts_per_page' => -1, 'no_found_rows' => true, 'suppress_filters' => false, );

            if ('page' === $post_type) {
                $base_args['meta_query'] = array(array('key' => '_puffergo_managed', 'compare' => 'EXISTS', ), );
            }

if ('' !== $default_slug) {
                $base_args['lang'] = $default_slug;
            } $total = count(get_posts(array_merge($base_args, array('post_status' => 'any', 'fields' => 'ids'))));
            $published_query = array_merge($base_args, array('post_status' => 'publish', 'orderby' => 'title', 'order' => 'ASC'));
            $published_posts = get_posts($published_query);
            $counts[ $post_type ] = array('total' => $total, 'published' => count($published_posts));

            foreach ($published_posts as $post) {
                $translations = array();

                foreach ($target_languages as $language) {
                    $translations[ $language['slug'] ] = PufferGo_Page_Translator::status_for($post->ID, $language['slug']);
                } $items[] = array('id' => $post->ID, 'postType' => $post_type, 'title' => $post->post_title, 'editUrl' => (string) get_edit_post_link($post->ID, 'raw'), 'viewUrl' => (string) get_permalink($post->ID), 'translations' => $translations, );
            }
        }

return $items;
    }

    private static function module_enabled_for_post_type(string $post_type): bool
    {
        $module_key = array_search($post_type, PufferGo_Module_Settings::MODULES, true);

        return false === $module_key || ! in_array($module_key, PufferGo_Module_Settings::PAUSED_MODULES, true);
    }

    public function page_status(WP_REST_Request $request): WP_REST_Response
    {
        $post_id = (int) $request->get_param('postId');
        $base = array('polylangActive' => PufferGo_Polylang::is_active(), 'hasApiKey' => ! empty(get_option('puffergo_api_key', '')), 'postLanguage' => null, 'defaultLanguage' => null, 'isSource' => true, 'sourcePage' => null, 'selfStatus' => null, 'targetLanguages' => array(), );

        if (! $base['polylangActive'] || $post_id <= 0) {
            return new WP_REST_Response($base, 200);
        } $post_lang_slug = PufferGo_Polylang::get_post_language($post_id);
        $default_slug = PufferGo_Polylang::default_language();
        $languages = PufferGo_Polylang::languages();

        foreach ($languages as $language) {
            if ($language['slug'] === $post_lang_slug) {
                $base['postLanguage'] = $language;
            }

if ($language['slug'] === $default_slug) {
                $base['defaultLanguage'] = $language;
            }
        } $base['isSource'] = ('' === $post_lang_slug) || ($post_lang_slug === $default_slug);

        if (! $base['isSource']) {
            $source_id = PufferGo_Polylang::get_translation($post_id, $default_slug);

            if ($source_id > 0 && $source_id !== $post_id) {
                $base['sourcePage'] = array('id' => $source_id, 'title' => (string) get_post_field('post_title', $source_id), 'editUrl' => (string) get_edit_post_link($source_id, 'raw'), );
                $base['selfStatus'] = PufferGo_Page_Translator::status_for($source_id, $post_lang_slug);
            }

return new WP_REST_Response($base, 200);
        } $targets = array();

        foreach ($languages as $language) {
            if ($language['slug'] === $post_lang_slug) {
                continue;
            } $status = PufferGo_Page_Translator::status_for($post_id, $language['slug']);
            $targets[] = array_merge($language, $status, array('navMenu' => self::nav_menu_payload($language['slug'])));
        } $base['targetLanguages'] = $targets;

        return new WP_REST_Response($base, 200);
    }

    public function translate(WP_REST_Request $request): WP_REST_Response
    {
        $post_id = (int) $request->get_param('postId');
        $lang = (string) $request->get_param('lang');
        $publish = (bool) $request->get_param('publish');

        if ($post_id <= 0 || '' === $lang) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Missing page or language.', 'puffergo'), ), 400);
        }

if (! PufferGo_Polylang::is_active()) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Polylang is not active.', 'puffergo'), ), 409);
        }

try {
            $result = PufferGo_Page_Translator::translate_post($post_id, $lang, $publish);
            $nav_status = PufferGo_Nav_Menu_Translator::status_for($lang)['status'];

            if (in_array($nav_status, array('none', 'failed'), true)) {
                PufferGo_Nav_Menu_Translator::translate_menus($lang);
            } $result['navMenu'] = self::nav_menu_payload($lang);

            return new WP_REST_Response(array('success' => true, 'data' => $result, ), 200);
        } catch (PufferGo_API_Exception $e) {
            $code = $e->getCode();

            return new WP_REST_Response($e->toArray(), ($code >= 400 && $code < 600) ? $code : 500);
        } catch (Exception $e) {
            $code = $e->getCode();
            $status = ($code >= 400 && $code < 600) ? $code : 500;

            return new WP_REST_Response(array('success' => false, 'message' => $e->getMessage(), ), $status);
        }
    }

    public function ensure_draft(WP_REST_Request $request): WP_REST_Response
    {
        $post_id = (int) $request->get_param('postId');
        $lang = (string) $request->get_param('lang');

        if ($post_id <= 0 || '' === $lang) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Missing page or language.', 'puffergo'), ), 400);
        }

if (! PufferGo_Polylang::is_active()) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Polylang is not active.', 'puffergo'), ), 409);
        }

try {
            $result = PufferGo_Page_Translator::ensure_manual_draft($post_id, $lang);

            return new WP_REST_Response(array('success' => true, 'data' => $result, ), 200);
        } catch (Exception $e) {
            $code = $e->getCode();
            $status = ($code >= 400 && $code < 600) ? $code : 500;

            return new WP_REST_Response(array('success' => false, 'message' => $e->getMessage(), ), $status);
        }
    }

    public function translate_menu(WP_REST_Request $request): WP_REST_Response
    {
        $lang = (string) $request->get_param('lang');

        if ('' === $lang) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Missing language.', 'puffergo'), ), 400);
        }

if (! PufferGo_Polylang::is_active()) {
            return new WP_REST_Response(array('success' => false, 'message' => __('Polylang is not active.', 'puffergo'), ), 409);
        } $status = PufferGo_Nav_Menu_Translator::translate_menus($lang);

        return new WP_REST_Response(array('success' => 'failed' !== $status['status'], 'data' => $status, ), 200);
    }

    public function get_context(): WP_REST_Response
    {
        $stored = get_option(self::CONTEXT_OPTION, array());

        if (! is_array($stored)) {
            $stored = array();
        }

return self::context_response(array_merge(self::default_context(), $stored));
    }

    private static function context_response(array $context): WP_REST_Response
    {
        $context['defaultInstructions'] = PufferGo_Translation_Client::DEFAULT_INSTRUCTIONS;

        return new WP_REST_Response($context, 200);
    }

    public function save_context(WP_REST_Request $request): WP_REST_Response
    {
        $stored = get_option(self::CONTEXT_OPTION, array());

        if (! is_array($stored)) {
            $stored = array();
        } $context = array_merge(self::default_context(), $stored);

        if (null !== $request->get_param('instructions')) {
            $instructions = (string) $request->get_param('instructions');

            if (function_exists('mb_substr')) {
                $instructions = mb_substr($instructions, 0, self::CONTEXT_INSTRUCTIONS_MAX_LENGTH);
            } else {
                $instructions = substr($instructions, 0, self::CONTEXT_INSTRUCTIONS_MAX_LENGTH);
            } $context['instructions'] = $instructions;
        } update_option(self::CONTEXT_OPTION, $context, false);

        return self::context_response($context);
    }

    private static function nav_menu_payload(string $lang): ?array
    {
        $status = PufferGo_Nav_Menu_Translator::current_status($lang);

        return ('none' === $status['status']) ? null : $status;
    }
}
