<?php
/**
 * REST API class - provides REST endpoints for translations
 *
 * @package LangForge
 */

if (!defined('ABSPATH')) {
    exit;
}

class LF_Rest_Api {

    private static $instance = null;
    private $namespace = 'langforge/v1';

    public static function instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action('rest_api_init', [$this, 'register_routes']);
        add_action('rest_api_init', [$this, 'register_post_fields']);
    }

    /**
 * Register REST API routes
 */
    public function register_routes() {
        // GET /langforge/v1/languages (requires auth - prevents site structure enumeration)
        register_rest_route($this->namespace, '/languages', [
            'methods' => 'GET',
            'callback' => [$this, 'get_languages'],
            'permission_callback' => [$this, 'edit_permission_check'],
        ]);

        // GET /langforge/v1/translations/<post_id> (requires auth)
        register_rest_route($this->namespace, '/translations/(?P<post_id>\d+)', [
            'methods' => 'GET',
            'callback' => [$this, 'get_translations'],
            'permission_callback' => [$this, 'edit_permission_check'],
            'args' => [
                'post_id' => [
                    'required' => true,
                    'type' => 'integer',
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        // POST /langforge/v1/translations
        register_rest_route($this->namespace, '/translations', [
            'methods' => 'POST',
            'callback' => [$this, 'create_translation_link'],
            'permission_callback' => [$this, 'edit_permission_check'],
            'args' => [
                'post_id' => ['required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint'],
                'target_post_id' => ['required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint'],
                'language' => ['required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field'],
            ],
        ]);

        // DELETE /langforge/v1/translations/<post_id>/<lang>
        register_rest_route($this->namespace, '/translations/(?P<post_id>\d+)/(?P<lang>[a-z]{2,5})', [
            'methods' => 'DELETE',
            'callback' => [$this, 'delete_translation_link'],
            'permission_callback' => [$this, 'edit_permission_check'],
            'args' => [
                'post_id' => ['required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint'],
                'lang' => ['required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field'],
            ],
        ]);

        // GET /langforge/v1/translation-status
        register_rest_route($this->namespace, '/translation-status', [
            'methods' => 'GET',
            'callback' => [$this, 'get_translation_status'],
            'permission_callback' => [$this, 'edit_permission_check'],
            'args' => [
                'post_type' => ['type' => 'string', 'default' => 'post'],
            ],
        ]);
    }

    /**
 * Register language/translations fields on all post type REST responses
 */
    public function register_post_fields() {
        $post_types = get_post_types(['show_in_rest' => true], 'names');

        foreach ($post_types as $post_type) {
            register_rest_field($post_type, 'lf_language', [
                'get_callback' => [$this, 'get_post_language_field'],
                'update_callback' => [$this, 'update_post_language_field'],
                'schema' => [
                    'description' => 'Post language code',
                    'type' => 'string',
                ],
            ]);

            register_rest_field($post_type, 'lf_translations', [
                'get_callback' => [$this, 'get_post_translations_field'],
                'schema' => [
                    'description' => 'Translation IDs keyed by language code',
                    'type' => 'object',
                ],
            ]);
        }
    }

    /**
 * GET /languages - List all active languages
 */
    public function get_languages($request) {
        $languages = LF_Core::instance()->get_active_languages();
        $default = LF_Core::instance()->get_default_language();
        $current = LF_Core::instance()->get_current_language();

        $result = [];
        foreach ($languages as $code => $lang) {
            $result[] = [
                'code' => $code,
                'name' => $lang['name'],
                'native_name' => $lang['native_name'],
                'locale' => $lang['locale'],
                'flag' => LF_Core::instance()->get_flag_url($lang['flag']),
                'is_default' => ($code === $default),
                'is_current' => ($code === $current),
                'url' => LF_Core::instance()->get_language_url($code),
            ];
        }

        return rest_ensure_response($result);
    }

    /**
 * GET /translations/<post_id>
 */
    public function get_translations($request) {
        $post_id = (int) $request['post_id'];
        $post = get_post($post_id);

        if (!$post) {
            return new WP_Error('not_found', __('Post not found', 'langforge'), ['status' => 404]);
        }

        if (!current_user_can('edit_post', $post_id)) {
            return new WP_Error('forbidden', __('You are not allowed to view translations of this post.', 'langforge'), ['status' => 403]);
        }

        $translations = LF_Post_Translation::instance()->get_translations($post_id);
        $language = get_post_meta($post_id, '_lf_language', true);

        $result = [
            'post_id' => $post_id,
            'language' => $language ?: LF_Core::instance()->get_default_language(),
            'translations' => [],
        ];

        foreach ($translations as $lang => $trans_id) {
            $trans_post = get_post($trans_id);
            if ($trans_post) {
                $result['translations'][$lang] = [
                    'id' => $trans_id,
                    'title' => $trans_post->post_title,
                    'status' => $trans_post->post_status,
                    'edit_link' => get_edit_post_link($trans_id, 'raw'),
                    'permalink' => get_permalink($trans_id),
                ];
            }
        }

        return rest_ensure_response($result);
    }

    /**
 * POST /translations - Create translation link
 */
    public function create_translation_link($request) {
        $post_id = (int) $request['post_id'];
        $target_post_id = (int) $request['target_post_id'];
        $language = sanitize_text_field($request['language']);

        if (!get_post($post_id) || !get_post($target_post_id)) {
            return new WP_Error('not_found', __('Post not found', 'langforge'), ['status' => 404]);
        }
        if ($err = LF_Post_Translation::instance()->require_language_available($language)) {
            return $err;
        }

        // BOLA guard: linking translations mutates _lf_language meta and the
        // translation group on BOTH posts — without per-post checks any author
        // can rewire any other author's translation linkage.
        if (!current_user_can('edit_post', $post_id) || !current_user_can('edit_post', $target_post_id)) {
            return new WP_Error('forbidden', __('You are not allowed to edit one of these posts.', 'langforge'), ['status' => 403]);
        }

        LF_Post_Translation::instance()->set_post_language($target_post_id, $language);
        LF_Post_Translation::instance()->link_translations($post_id, $target_post_id);

        return rest_ensure_response([
            'success' => true,
            'message' => __('Translation linked', 'langforge'),
        ]);
    }

    /**
 * DELETE /translations/<post_id>/<lang>
 */
    public function delete_translation_link($request) {
        $post_id = (int) $request['post_id'];
        $language = $request['lang'];

        if (!get_post($post_id)) {
            return new WP_Error('not_found', __('Post not found', 'langforge'), ['status' => 404]);
        }

        if (!current_user_can('edit_post', $post_id)) {
            return new WP_Error('forbidden', __('You are not allowed to edit this post.', 'langforge'), ['status' => 403]);
        }

        LF_Post_Translation::instance()->unlink_translation($post_id, $language);

        return rest_ensure_response([
            'success' => true,
            'message' => __('Translation unlinked', 'langforge'),
        ]);
    }

    /**
 * GET /translation-status - Overview of translation completeness
 */
    public function get_translation_status($request) {
        global $wpdb;

        $post_type = sanitize_text_field($request['post_type']);
        $languages = LF_Core::instance()->get_active_languages();
        $default_lang = LF_Core::instance()->get_default_language();

        // Count total posts in default language
        $total = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- own table from $wpdb->prefix; one-time/admin read
            "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p
            INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = %s AND p.post_status = 'publish'
            AND pm.meta_key = '_lf_language' AND pm.meta_value = %s",
            $post_type, $default_lang
        ));

        $stats = [];
        foreach ($languages as $code => $lang) {
            if ($code === $default_lang) {
                $stats[$code] = [
                    'name' => $lang['native_name'],
                    'total' => (int) $total,
                    'translated' => (int) $total,
                    'percentage' => 100,
                ];
                continue;
            }

            $translated = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- own table from $wpdb->prefix; one-time/admin read
                "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p
                INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
                WHERE p.post_type = %s AND p.post_status = 'publish'
                AND pm.meta_key = '_lf_language' AND pm.meta_value = %s",
                $post_type, $code
            ));

            $stats[$code] = [
                'name' => $lang['native_name'],
                'total' => (int) $total,
                'translated' => (int) $translated,
                'percentage' => $total > 0 ? round(($translated / $total) * 100) : 0,
            ];
        }

        return rest_ensure_response($stats);
    }

    /**
 * REST field callbacks
 */
    public function get_post_language_field($post) {
        $lang = get_post_meta($post['id'], '_lf_language', true);
        return $lang ?: LF_Core::instance()->get_default_language();
    }

    public function update_post_language_field($value, $post) {
        if (!current_user_can('edit_post', $post->ID)) {
            return new WP_Error('forbidden', __('You are not allowed to edit this post.', 'langforge'), ['status' => 403]);
        }
        $language = sanitize_text_field($value);
        if ($err = LF_Post_Translation::instance()->require_language_available($language)) {
            return $err;
        }
        LF_Post_Translation::instance()->set_post_language($post->ID, $language);
        return true;
    }

    public function get_post_translations_field($post) {
        $translations = LF_Post_Translation::instance()->get_translations($post['id']);
        if (!is_array($translations)) {
            return $translations;
        }
        // Only expose translations the requester may read, so a public post's
        // REST entry doesn't leak draft/private translation topology.
        $visible = [];
        foreach ($translations as $lang => $tid) {
            if (current_user_can('read_post', (int) $tid)) {
                $visible[$lang] = $tid;
            }
        }
        return $visible;
    }

    /**
 * Permission check - user can edit posts
 */
    public function edit_permission_check($request) {
        return current_user_can('edit_posts');
    }
}
