<?php

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

class Ansico_Diagnosekoder_REST {
    public static function init() {
        add_action('rest_api_init', [__CLASS__, 'register_routes']);
    }

    public static function register_routes() {
        register_rest_route('ansico-diagnosekoder/v1', '/search', [
            'methods'  => WP_REST_Server::READABLE,
            'callback' => [__CLASS__, 'search'],
            'permission_callback' => '__return_true',
            'args' => [
                'q' => [
                    'type' => 'string',
                    'required' => false,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'limit' => [
                    'type' => 'integer',
                    'required' => false,
                    'default' => 50,
                    'sanitize_callback' => 'absint',
                ],
                'page_id' => [
                    'type' => 'integer',
                    'required' => false,
                    'default' => 0,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ansico-diagnosekoder/v1', '/page-state', [
            'methods'  => WP_REST_Server::READABLE,
            'callback' => [__CLASS__, 'page_state'],
            'permission_callback' => '__return_true',
            'args' => [
                'page_id' => [
                    'type' => 'integer',
                    'required' => false,
                    'default' => 0,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ansico-diagnosekoder/v1', '/content-search', [
            'methods'  => WP_REST_Server::READABLE,
            'callback' => [__CLASS__, 'content_search'],
            'permission_callback' => static function () {
                return is_user_logged_in();
            },
            'args' => [
                'q' => [
                    'type' => 'string',
                    'required' => false,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'limit' => [
                    'type' => 'integer',
                    'required' => false,
                    'default' => 8,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ansico-diagnosekoder/v1', '/favorites', [
            'methods'  => WP_REST_Server::CREATABLE,
            'callback' => [__CLASS__, 'toggle_favorite'],
            'permission_callback' => static function () {
                return is_user_logged_in();
            },
            'args' => [
                'code' => [
                    'type' => 'string',
                    'required' => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'page_id' => [
                    'type' => 'integer',
                    'required' => true,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ansico-diagnosekoder/v1', '/links', [
            'methods'  => WP_REST_Server::CREATABLE,
            'callback' => [__CLASS__, 'save_link'],
            'permission_callback' => static function () {
                return is_user_logged_in();
            },
            'args' => [
                'code' => [
                    'type' => 'string',
                    'required' => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'url' => [
                    'type' => 'string',
                    'required' => true,
                ],
                'page_id' => [
                    'type' => 'integer',
                    'required' => true,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ansico-diagnosekoder/v1', '/links', [
            'methods'  => WP_REST_Server::DELETABLE,
            'callback' => [__CLASS__, 'remove_link'],
            'permission_callback' => static function () {
                return is_user_logged_in();
            },
            'args' => [
                'code' => [
                    'type' => 'string',
                    'required' => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'page_id' => [
                    'type' => 'integer',
                    'required' => true,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);
    }

    public static function search(WP_REST_Request $request) {
        $query = (string) $request->get_param('q');
        $limit = (int) $request->get_param('limit');
        $page_id = absint($request->get_param('page_id'));
        if (!$page_id) {
            $page_id = self::get_results_page_id();
        }
        $limit = $limit > 0 ? min($limit, 100) : 50;

        $favorite_codes = self::get_page_favorites($page_id);
        $links = self::get_page_links($page_id);

        $response = rest_ensure_response([
            'query' => $query,
            'results' => Ansico_Diagnosekoder_Parser::search($query, $limit, $favorite_codes, $links),
            'meta' => get_option(ANSICO_DIAGNOSEKODER_OPTION_META, []),
            'favorites' => $favorite_codes,
            'links' => $links,
            'is_logged_in' => is_user_logged_in(),
            'page_id' => $page_id,
        ]);

        $response->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
        $response->header('Pragma', 'no-cache');
        return $response;
    }

    public static function page_state(WP_REST_Request $request) {
        $page_id = absint($request->get_param('page_id'));
        if (!$page_id) {
            $page_id = self::get_results_page_id();
        }

        $response = rest_ensure_response([
            'page_id' => $page_id,
            'favorites' => self::get_page_favorites($page_id),
            'links' => self::get_page_links($page_id),
        ]);
        $response->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
        $response->header('Pragma', 'no-cache');
        return $response;
    }

    public static function content_search(WP_REST_Request $request) {
        $query = trim((string) $request->get_param('q'));
        $limit = (int) $request->get_param('limit');
        $limit = $limit > 0 ? min($limit, 20) : 8;

        if ($query === '') {
            return rest_ensure_response(['results' => []]);
        }

        $all_post_types = get_post_types([], 'objects');
        $excluded_types = ['attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset', 'oembed_cache', 'user_request', 'wp_block', 'wp_navigation', 'wp_template', 'wp_template_part', 'wp_global_styles', 'wp_font_family', 'wp_font_face'];

        $post_types = [];
        foreach ($all_post_types as $post_type => $object) {
            if (in_array($post_type, $excluded_types, true)) {
                continue;
            }

            if (strpos($post_type, 'wp_') === 0) {
                continue;
            }

            // Include posts, pages, and all custom post types that can reasonably have frontend URLs,
            // even when the CPT is excluded from normal WordPress search.
            if (!empty($object->public) || !empty($object->publicly_queryable) || !empty($object->show_ui)) {
                $post_types[] = $post_type;
            }
        }

        $post_types = array_values(array_unique($post_types));

        if (empty($post_types)) {
            $post_types = ['page', 'post'];
        }

        $posts = get_posts([
            'post_type' => $post_types,
            'post_status' => 'publish',
            's' => $query,
            'posts_per_page' => $limit,
            'orderby' => 'relevance',
            'order' => 'DESC',
            'suppress_filters' => false,
        ]);

        $results = [];
        foreach ($posts as $post) {
            $results[] = [
                'id' => (int) $post->ID,
                'title' => get_the_title($post),
                'url' => get_permalink($post),
                'type' => get_post_type($post),
            ];
        }

        return rest_ensure_response(['results' => $results]);
    }

    public static function toggle_favorite(WP_REST_Request $request) {
        $code = self::normalize_code((string) $request->get_param('code'));
        $page_id = absint($request->get_param('page_id'));
        if (!$page_id) {
            $page_id = self::get_results_page_id();
        }

        if ($code === '') {
            return new WP_Error('ansico_empty_code', __('Der mangler en kode.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        if (!$page_id || get_post_status($page_id) === false) {
            return new WP_Error('ansico_invalid_page', __('Der mangler en gyldig side.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        $favorites = self::get_page_favorites($page_id);
        $index = array_search($code, $favorites, true);
        $is_favorite = false;

        if ($index === false) {
            $favorites[] = $code;
            $is_favorite = true;
        } else {
            unset($favorites[$index]);
            $favorites = array_values($favorites);
        }

        update_post_meta($page_id, ANSICO_DIAGNOSEKODER_PAGE_FAVORITES_META, $favorites);

        return rest_ensure_response([
            'code' => $code,
            'is_favorite' => $is_favorite,
            'favorites' => $favorites,
            'page_id' => $page_id,
        ]);
    }

    public static function get_page_favorites($page_id) {
        $page_id = absint($page_id);
        if (!$page_id) {
            return [];
        }

        $favorites = get_post_meta($page_id, ANSICO_DIAGNOSEKODER_PAGE_FAVORITES_META, true);
        if (!is_array($favorites)) {
            return [];
        }

        $favorites = array_map([__CLASS__, 'normalize_code'], $favorites);
        return array_values(array_unique(array_filter($favorites)));
    }

    public static function save_link(WP_REST_Request $request) {
        $code = self::normalize_code((string) $request->get_param('code'));
        $url = esc_url_raw((string) $request->get_param('url'));
        $page_id = absint($request->get_param('page_id'));
        if (!$page_id) {
            $page_id = self::get_results_page_id();
        }

        if ($code === '') {
            return new WP_Error('ansico_empty_code', __('Der mangler en kode.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        if (!$url || !wp_http_validate_url($url)) {
            return new WP_Error('ansico_invalid_url', __('URL-adressen er ikke gyldig.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        if (!$page_id || get_post_status($page_id) === false) {
            return new WP_Error('ansico_invalid_page', __('Der mangler en gyldig side.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        $links = self::get_page_links($page_id);
        $links[$code] = $url;
        update_post_meta($page_id, ANSICO_DIAGNOSEKODER_PAGE_LINKS_META, $links);

        return rest_ensure_response([
            'code' => $code,
            'url' => $url,
            'links' => $links,
            'page_id' => $page_id,
        ]);
    }

    public static function remove_link(WP_REST_Request $request) {
        $code = self::normalize_code((string) $request->get_param('code'));
        $page_id = absint($request->get_param('page_id'));
        if (!$page_id) {
            $page_id = self::get_results_page_id();
        }

        if (!$page_id || get_post_status($page_id) === false) {
            return new WP_Error('ansico_invalid_page', __('Der mangler en gyldig side.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        $links = self::get_page_links($page_id);
        if ($code === '') {
            return new WP_Error('ansico_empty_code', __('Der mangler en kode.', 'ansico-diagnosekoder'), ['status' => 400]);
        }

        unset($links[$code]);
        update_post_meta($page_id, ANSICO_DIAGNOSEKODER_PAGE_LINKS_META, $links);

        return rest_ensure_response([
            'code' => $code,
            'links' => $links,
            'page_id' => $page_id,
        ]);
    }

    public static function get_page_links($page_id) {
        $page_id = absint($page_id);
        if (!$page_id) {
            return [];
        }

        $links = get_post_meta($page_id, ANSICO_DIAGNOSEKODER_PAGE_LINKS_META, true);
        if (!is_array($links)) {
            return [];
        }

        $normalized = [];
        foreach ($links as $code => $url) {
            $normalized_code = self::normalize_code((string) $code);
            $normalized_url = esc_url_raw((string) $url);
            if ($normalized_code === '' || $normalized_url === '' || !wp_http_validate_url($normalized_url)) {
                continue;
            }
            $normalized[$normalized_code] = $normalized_url;
        }

        return $normalized;
    }

    protected static function get_results_page_id() {
        $results_url = (string) get_option(ANSICO_DIAGNOSEKODER_OPTION_RESULTS_URL, '');
        if ($results_url === '') {
            return 0;
        }

        return absint(url_to_postid($results_url));
    }

    protected static function normalize_code($code) {
        $code = sanitize_text_field((string) $code);
        $code = preg_replace('/\s+/', '', $code);
        return strtoupper((string) $code);
    }
}
