<?php

namespace Sikshya\Api;

use WP_REST_Request;
use WP_REST_Response;

class CourseService
{
    /**
     * Get all courses
     */
    public function getCourses(WP_REST_Request $request): WP_REST_Response
    {
        $args = [
            'post_type' => 'sikshya_course',
            'post_status' => 'publish',
            'posts_per_page' => $request->get_param('per_page') ?: 10,
            'paged' => $request->get_param('page') ?: 1,
        ];
        $query = new \WP_Query($args);
        $courses = [];
        foreach ($query->posts as $post) {
            $courses[] = $this->formatCourse($post);
        }
        return new WP_REST_Response([
            'courses' => $courses,
            'total' => $query->found_posts,
            'pages' => $query->max_num_pages,
        ]);
    }

    /**
     * Create a new course
     */
    public function createCourse(WP_REST_Request $request): WP_REST_Response
    {
        $data = $request->get_json_params();
        $post_id = wp_insert_post([
            'post_type' => 'sikshya_course',
            'post_title' => sanitize_text_field($data['title'] ?? ''),
            'post_content' => wp_kses_post($data['content'] ?? ''),
            'post_status' => 'publish',
        ]);
        if (is_wp_error($post_id)) {
            return new WP_REST_Response(['error' => $post_id->get_error_message()], 400);
        }
        return $this->getCourse(new WP_REST_Request('GET', '', ['id' => $post_id]));
    }

    /**
     * Get a single course
     */
    public function getCourse(WP_REST_Request $request): WP_REST_Response
    {
        $id = $request->get_param('id');
        $post = get_post($id);
        if (!$post || $post->post_type !== 'sikshya_course') {
            return new WP_REST_Response(['error' => __('Course not found', 'sikshya')], 404);
        }
        return new WP_REST_Response($this->formatCourse($post));
    }

    /**
     * Update a course
     */
    public function updateCourse(WP_REST_Request $request): WP_REST_Response
    {
        $id = $request->get_param('id');
        $data = $request->get_json_params();
        $postarr = [
            'ID' => $id,
            'post_title' => sanitize_text_field($data['title'] ?? ''),
            'post_content' => wp_kses_post($data['content'] ?? ''),
        ];
        $result = wp_update_post($postarr, true);
        if (is_wp_error($result)) {
            return new WP_REST_Response(['error' => $result->get_error_message()], 400);
        }
        return $this->getCourse(new WP_REST_Request('GET', '', ['id' => $id]));
    }

    /**
     * Delete a course
     */
    public function deleteCourse(WP_REST_Request $request): WP_REST_Response
    {
        $id = $request->get_param('id');
        $result = wp_delete_post($id, true);
        if (!$result) {
            return new WP_REST_Response(['error' => __('Failed to delete course', 'sikshya')], 400);
        }
        return new WP_REST_Response(['success' => true]);
    }

    /**
     * Format course data for API response.
     *
     * SECURITY: this shape is served publicly (see {@see Api} — the READ
     * routes for `/courses` and `/courses/{id}` deliberately allow
     * anonymous access so third-party catalog integrations can list
     * published courses). We therefore serialise only the small set of
     * publicly-safe meta keys instead of returning `get_post_meta($id)`
     * verbatim, which would leak every internal `_sikshya_*` scratchpad,
     * `_edit_lock`, unpublished sale schedules, instructor-facing notes,
     * and any third-party plugin's post meta.
     *
     * Allow list matches what the curated {@see PublicApiRoutes} already
     * exposes for the catalog surface (`sikshya_course_price`,
     * `sikshya_course_duration`, `sikshya_course_level`). New public
     * fields should be added here explicitly, not by widening the dump.
     */
    private function formatCourse($post): array
    {
        return [
            'id' => $post->ID,
            'title' => $post->post_title,
            'content' => $post->post_content,
            'excerpt' => $post->post_excerpt,
            'status' => $post->post_status,
            'author' => $post->post_author,
            'date' => $post->post_date,
            'categories' => wp_get_post_terms($post->ID, 'sikshya_course_category', ['fields' => 'names']),
            'tags' => wp_get_post_terms($post->ID, 'sikshya_course_tag', ['fields' => 'names']),
            'meta' => self::publicCourseMeta((int) $post->ID),
            'permalink' => get_permalink($post->ID),
        ];
    }

    /**
     * Return public course meta as an allowlisted subset in the same
     * `array<string, array<int, string>>` shape as WordPress's own
     * `get_post_meta($id)` (with no key) — each key maps to an array of
     * one string.
     *
     * SECURITY: the previous shape here was a flat `array<string, string>`
     * which is safer but broke the public REST contract for third-party
     * catalog consumers that read `meta.sikshya_course_price[0]`.
     * Preserving WP's shape means those consumers keep working; the
     * allowlist is what actually prevents the leak — no `_edit_lock`,
     * no unpublished sale schedules, no third-party plugin meta.
     *
     * @return array<string, array<int, string>>
     */
    private static function publicCourseMeta(int $post_id): array
    {
        $allowed = [
            'sikshya_course_price',
            'sikshya_course_duration',
            'sikshya_course_level',
        ];
        $out = [];
        foreach ($allowed as $key) {
            $value = get_post_meta($post_id, $key, true);
            if ($value === '' || $value === null || $value === false) {
                continue;
            }
            $out[$key] = [is_scalar($value) ? (string) $value : ''];
        }
        return $out;
    }
}
