<?php

namespace Yuvayana\Acadlix\Common\REST\Front;

use WP_Error;
use WP_REST_Server;
use Yuvayana\Acadlix\Common\Models\CourseEnrollment;
use Yuvayana\Acadlix\Common\Models\Order;

defined('ABSPATH') || exit();

class FrontDashboardController
{
  protected $namespace = 'acadlix/v1';
  protected $base = 'front-dashboard';

  public function register_routes()
  {

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-courses',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_courses'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-course-by-id',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_course_by_id'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-update-lesson-time',
      [
        [
          'methods' => WP_REST_Server::CREATABLE,
          'callback' => [$this, 'post_update_lesson_time'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-update-lesson-time-statistics',
      [
        [
          'methods' => WP_REST_Server::EDITABLE,
          'callback' => [$this, 'post_update_lesson_time_statistics'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-set-active',
      [
        [
          'methods' => WP_REST_Server::CREATABLE,
          'callback' => [$this, 'post_set_active'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-mark-as-complete',
      [
        [
          'methods' => WP_REST_Server::CREATABLE,
          'callback' => [$this, 'post_mark_as_complete'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-mark-as-incomplete',
      [
        [
          'methods' => WP_REST_Server::CREATABLE,
          'callback' => [$this, 'post_mark_as_incomplete'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-purchases',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_purchases'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-wishlist',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_wishlist'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-profile',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_profile'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-update-user-photo',
      [
        [
          'methods' => WP_REST_Server::EDITABLE,
          'callback' => [$this, 'post_update_user_photo'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-update-user-profile',
      [
        [
          'methods' => WP_REST_Server::EDITABLE,
          'callback' => [$this, 'post_update_user_profile'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/post-update-user-password',
      [
        [
          'methods' => WP_REST_Server::EDITABLE,
          'callback' => [$this, 'post_update_user_password'],
          'permission_callback' => [$this, 'check_permission'],
        ],
      ]
    );

    register_rest_route(
      $this->namespace,
      '/' . $this->base . '/get-user-certificate-by-id',
      [
        [
          'methods' => WP_REST_Server::READABLE,
          'callback' => [$this, 'get_user_certificate_by_id'],
          'permission_callback' => function ($request) {
            return wp_verify_nonce(
              $request->get_header('X-WP-Nonce'),
              'wp_rest'
            );
          },
        ],
      ]
    );
  }

  public function get_user_courses($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_courses_params', $request->get_params(), $request);

    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? 0;
    if (empty($userId)) {
      return new WP_Error('no_data_found', __('Required user_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_courses_payload', [
      'user_id' => intval($userId),
      'page' => intval($params['page'] ?? 0),
      'pageSize' => intval($params['pageSize'] ?? 10),
      'search' => $params['search'] ?? null,
      'category_id' => $params['category_id'] ?? null,
    ], $params);

    $skip = $payload['page'] * $payload['pageSize'];

    // Fetch purchased courses
    // $result = acadlix()
    //   ->model()
    //   ->course()
    //   ->getPurchasedCourses(
    //     $payload['user_id'],
    //     $payload['search'],
    //     $skip,
    //     $payload['pageSize'],
    //     [],
    //     $payload['category_id']
    //   );

    $enrolledCourses = acadlix()
      ->model()
      ->courseEnrollment()
      ->getEnrolledCourses(
        $payload['user_id'],
        $payload['search'],
        $skip,
        $payload['pageSize'],
        ['course'],
        $payload['category_id']
      );

    $categoryIds = $enrolledCourses['category_ids'] ?? [];
    $categories = acadlix()
      ->model()
      ->wpTermTaxonomy()
      ->ofCourseCategory()
      ->with('term')
      ->where('count', '>', 0)
      ->whereHas('term', function ($query) use ($categoryIds) {
        $query->whereIn('term_id', $categoryIds);
      })
      ->get();

    $res = [
      'categories' => $categories,
      'total' => $enrolledCourses['total'],
      'courses' => $enrolledCourses['courses'],
      // 'enrolled_courses' => $enrolledCourses,
    ];

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_courses', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_courses_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }


  public function get_user_course_by_id($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_course_by_id_params', $request->get_params(), $request);

    $courseId = $params['course_id'] ?? $request->get_param('course_id') ?? null;
    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? null;

    $required_fields = array('course_id', 'user_id');
    foreach ($required_fields as $field) {
      $param = !empty($params[$field]) ? $params[$field] : $request->get_param($field);
      if (empty($param)) {
        /* translators: %s is the required field */
        $errors[] = sprintf(__('The %s parameter is required.', 'acadlix'), $field);
      }
    }

    if (!empty($errors)) {
      return new WP_Error('missing_params', implode(' ', $errors), array('status' => 400));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_course_by_id_payload', [
      'course_id' => intval($courseId),
      'user_id' => intval($userId),
    ], $params);

    // Fetch course with sections and statistics
    $course = acadlix()
      ->model()
      ->course()
      ->with([
        'sections',
        'sections.contents' => function ($query) use ($payload) {
          $query->with([
            'course_statistics' => function ($query) use ($payload) {
              $query->where('user_id', $payload['user_id']);
            }
          ]);
        },
        'announcements',
      ])
      ->find($payload['course_id']);

    $course->completion_percentage = $course->getCourseCompletionPercentage($payload['user_id']);

    $course_statistics = acadlix()
      ->model()
      ->courseStatistic()
      ->where('course_id', $payload['course_id'])
      ->where('user_id', $payload['user_id'])
      ->where('is_active', true)
      ->first();

    if ($course_statistics) {
      $courseSectionContentId = $course_statistics->course_section_content_id ?? null;
    } else {
      $firstSection = $course->sections->first();
      $firstContent = $firstSection?->contents?->first();
      $courseSectionContentId = $firstContent?->ID ?? null;
    }

    $certificate = acadlix()
      ->model()
      ->userActivityMeta()
      ->ofCertificate()
      ->where('user_id', $payload['user_id'])
      ->where('type_id', $payload['course_id'])
      ->first();

    $res = [];
    if ($certificate) {
      $res['certificate'] = $certificate;
    }
    $res['course'] = $course;
    $res['course_section_content_id'] = $courseSectionContentId;

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_course_by_id', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_course_by_id_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_update_lesson_time($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_update_lesson_time_params', $request->get_params(), $request);

    $lessonId = $params['lesson_id'] ?? $request->get_param('lesson_id') ?? null;
    if (empty($lessonId)) {
      return new WP_Error('missing_params', __('The lesson_id parameter is required.', 'acadlix'), array('status' => 400));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_post_update_lesson_time_payload', [
      'lesson_id' => intval($lessonId),
      'hours' => intval($params['hours'] ?? 0),
      'minutes' => intval($params['minutes'] ?? 0),
      'seconds' => intval($params['seconds'] ?? 0),
    ], $params);

    // Prepare meta data with prefixed keys
    $meta = [
      'hours' => $payload['hours'],
      'minutes' => $payload['minutes'],
      'seconds' => $payload['seconds'],
    ];

    $meta = !empty($meta) && is_array($meta)
      ? acadlix()->helper()->cpt()->acadlix_add_prefix_meta_keys($meta, 'lesson')
      : [];

    // Check if lesson exists and update
    $lesson = acadlix()->model()->lesson()->ofLesson()->find($payload['lesson_id']);
    if ($lesson) {
      acadlix()->model()->lesson()->updateLesson($payload['lesson_id'], [], $meta);
    }

    $res = [
      'success' => true,
      'lesson' => acadlix()->model()->lesson()->ofLesson()->find($payload['lesson_id'])
    ];

    // 3) Lifecycle Action: allow listeners to react to the update
    do_action('acadlix_post_update_lesson_time', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_update_lesson_time_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_update_lesson_time_statistics($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_update_lesson_time_statistics_params', $request->get_params(), $request);

    $courseStatisticId = $params['course_statistic_id'] ?? $request->get_param('course_statistic_id') ?? null;
    $metaValue = $params['meta_value'] ?? $request->get_param('meta_value') ?? null;

    $required_fields = array('course_statistic_id', 'meta_value');
    foreach ($required_fields as $field) {
      $param = $params[$field] ?? $request->get_param($field) ?? null;
      if (empty($param)) {
        /* translators: %s is the required field */
        $errors[] = sprintf(__('The %s parameter is required.', 'acadlix'), $field);
      }
    }

    if (!empty($errors)) {
      return new WP_Error('missing_params', implode(' ', $errors), array('status' => 400));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_post_update_lesson_time_statistics_payload', [
      'course_statistic_id' => intval($courseStatisticId),
      'meta_value' => $metaValue,
    ], $params);

    // Update course statistic
    $courseStatistic = acadlix()->model()->courseStatistic()->find($payload['course_statistic_id']);
    if ($courseStatistic) {
      $courseStatistic->update([
        'meta_value' => $payload['meta_value']
      ]);
    }

    $res = [
      'success' => true,
      'course_statistic' => acadlix()->model()->courseStatistic()->find($payload['course_statistic_id'])
    ];

    // 3) Lifecycle Action: allow listeners to react to the update
    do_action('acadlix_post_update_lesson_time_statistics', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_update_lesson_time_statistics_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }
  public function post_set_active($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_set_active_params', $request->get_params(), $request);

    $courseId = $params['course_id'] ?? $request->get_param('course_id') ?? null;
    $courseSectionId = $params['course_section_id'] ?? $request->get_param('course_section_id') ?? null;
    $courseSectionContentId = $params['course_section_content_id'] ?? $request->get_param('course_section_content_id') ?? null;
    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? null;
    $metaType = $params['meta_type'] ?? $request->get_param('meta_type') ?? null;

    $required_fields = array('course_id', 'course_section_id', 'course_section_content_id', 'user_id');
    foreach ($required_fields as $field) {
      $param = !empty($params[$field]) ? $params[$field] : $request->get_param($field);
      if (empty($param)) {
        /* translators: %s is the required field */
        $errors[] = sprintf(__('The %s parameter is required.', 'acadlix'), $field);
      }
    }

    if (!empty($errors)) {
      return new WP_Error('missing_params', implode(' ', $errors), array('status' => 400));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_post_set_active_payload', [
      'course_section_id' => intval($courseSectionId),
      'course_id' => intval($courseId),
      'course_section_content_id' => intval($courseSectionContentId),
      'user_id' => intval($userId),
      'meta_type' => $metaType,
    ], $params);

    // Deactivate all existing course statistics for this user/course
    $course_statistics = acadlix()
      ->model()
      ->courseStatistic()
      ->where('course_id', $payload['course_id'])
      ->where('user_id', $payload['user_id'])
      ->get();

    $courseEnrollment = acadlix()
      ->model()
      ->courseEnrollment()
      ->where('course_id', $payload['course_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    if ($courseEnrollment) {
      $courseEnrollment->update([
        'course_section_content_id' => $payload['course_section_content_id'],
      ]);
      if ($courseEnrollment->started_at === null) {
        $courseEnrollment->update([
          'started_at' => current_time('mysql')
        ]);
      }
    }

    if ($course_statistics->count() > 0) {
      foreach ($course_statistics as $course_statistic) {
        $course_statistic->update([
          'is_active' => false
        ]);
      }
    }

    // Try to find or create active statistic
    $active_statistic = acadlix()
      ->model()
      ->courseStatistic()
      ->where('course_id', $payload['course_id'])
      ->where('course_section_content_id', $payload['course_section_content_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    if ($active_statistic) {
      $active_statistic->update([
        'is_active' => true
      ]);
      // 3a) Conditional action: existing statistic updated
      do_action('acadlix_post_set_active_updated', $active_statistic, $payload, $params);
    } else {
      $active_statistic = acadlix()
        ->model()
        ->courseStatistic()
        ->create([
          'course_id' => $payload['course_id'],
          'course_section_content_id' => $payload['course_section_content_id'],
          'user_id' => $payload['user_id'],
          'is_active' => true,
          'is_completed' => false,
          'meta_type' => $payload['meta_type'],
        ]);
      // 3b) Conditional action: new statistic created
      do_action('acadlix_post_set_active_created', $active_statistic, $payload, $params);
    }

    $res = [
      'active_statistic' => $active_statistic,
      'success' => true
    ];

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_set_active_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_mark_as_complete($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_mark_as_complete_params', $request->get_params(), $request);

    $required_fields = array('course_id', 'course_section_content_id', 'user_id');
    $errors = [];
    foreach ($required_fields as $field) {
      $param = $params[$field] ?? $request->get_param($field) ?? null;

      if (empty($param)) {
        /* translators: %s is the required field */
        $errors[] = sprintf(__('The %s parameter is required.', 'acadlix'), $field);
      }
    }

    if (!empty($errors)) {
      return new WP_Error('missing_params', implode(' ', $errors), array('status' => 400));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_post_mark_as_complete_payload', [
      'user_id' => intval($params['user_id'] ?? $request->get_param('user_id')),
      'course_id' => intval($params['course_id'] ?? $request->get_param('course_id')),
      'course_section_content_id' => intval($params['course_section_content_id'] ?? $request->get_param('course_section_content_id')),
    ], $params);

    $res = [
      'success' => true,
      'course_full_completed' => false,
      'course_completion_percentage' => 0,
      'active_statistic' => null,
    ];

    $active_statistic = acadlix()
      ->model()
      ->courseStatistic()
      ->where('course_id', $payload['course_id'])
      ->where('course_section_content_id', $payload['course_section_content_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    $courseEnrollment = acadlix()
      ->model()
      ->courseEnrollment()
      ->where('course_id', $payload['course_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    if ($active_statistic) {
      $active_statistic->update([
        'is_completed' => true
      ]);
      // 3a) Conditional action: existing statistic updated
      do_action('acadlix_post_mark_as_complete_updated', $active_statistic, $payload, $params);
    } else {
      $active_statistic = acadlix()
        ->model()
        ->courseStatistic()
        ->create([
          'course_id' => $payload['course_id'],
          'course_section_content_id' => $payload['course_section_content_id'],
          'user_id' => $payload['user_id'],
          'is_active' => true,
          'is_completed' => true,
        ]);
      // 3b) Conditional action: new statistic created
      do_action('acadlix_post_mark_as_complete_created', $active_statistic, $payload, $params);
    }

    $res['active_statistic'] = $active_statistic;

    // Save complete date
    if ($active_statistic) {
      acadlix()
        ->model()
        ->userActivityMeta()
        ->create([
          'user_id' => $payload['user_id'],
          'type' => 'course_statistic',
          'type_id' => $active_statistic->id,
          'meta_key' => 'course_statistic_complete_time', // phpcs:ignore
          'meta_value' => time(), // phpcs:ignore
        ]);
    }

    $course = acadlix()
      ->model()
      ->course()
      ->ofCourse()
      ->find($payload['course_id']);

    $course_completion_percentage = 0;
    if ($course) {
      $course_completion_percentage = $course->getCourseCompletionPercentage($payload['user_id']) ?? 0;

      $courseEnrollment->update([
        'progress_percent' => $course_completion_percentage,
      ]);

      $res['course_completion_percentage'] = $course_completion_percentage;
      if ($course_completion_percentage == 100) {

        $courseEnrollment->update([
          'status' => CourseEnrollment::STATUS_COMPLETED,
          'completed_at' => current_time('mysql'),
        ]);

        $res['course_full_completed'] = true;
        // handle certificate creation
        $certificate = acadlix()->model()->userActivityMeta()->ofCertificate()
          ->where('user_id', $payload['user_id'])
          ->where('type_id', $payload['course_id'])
          ->first();

        if (!$certificate && ($course->rendered_metas['enable_certificate'] ?? false)) {
          $custom_logo_id = get_theme_mod('custom_logo');
          $logo_url = wp_get_attachment_image_url($custom_logo_id, 'full');
          $certificate_id = acadlix()->helper()->acadlix_generate_certificate_id();

          // Construct mapping names efficiently
          $instructor_names = [];
          if (empty($course->users) || count($course->users) === 0) {
            $instructor_names[] = get_the_author_meta('display_name', $course->post_author);
          } else {
            foreach ($course->users as $u) {
              $instructor_names[] = get_the_author_meta('display_name', is_object($u) ? $u->ID : $u);
            }
          }
          $data = [
            "certificate_id" => $certificate_id,
            "logo" => $logo_url ?? "",
            "acadlix_certificate_authorised_name" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_authorised_name') ?? "",
            "acadlix_certificate_authorised_company" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_authorised_company') ?? "",
            "acadlix_certificate_show_instructor_name_on_certificate" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_show_instructor_name_on_certificate'),
            "acadlix_certificate_show_course_completion_date_on_certificate" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_show_course_completion_date_on_certificate'),
            "acadlix_certificate_signature" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_signature') ?? [],
            "template" =>
              acadlix()->helper()->acadlix_get_option('acadlix_certificate_template') ?? "classic-landscape",
            "instructor" => implode(', ', $instructor_names),
            "user_name" => get_the_author_meta('display_name', $payload['user_id']),
            "course_name" => $course->post_title ?? "",
            "completion_date" => time(),
          ];
          $certificate = acadlix()
            ->model()
            ->userActivityMeta()
            ->create([
              'user_id' => $payload['user_id'],
              'type' => 'certificate',
              'type_id' => $payload['course_id'], // Will be updated after certificate creation
              'meta_key' => 'certificate', // phpcs:ignore
              'meta_value' => $data, // phpcs:ignore
              'reference_id' => $certificate_id,
            ]);
          $res['certificate'] = $certificate;
        }

        // Operational hooks
        do_action('acadlix_course_completed', $payload['course_id'], $payload['user_id']);
        acadlix()->notifications()->email()->handleCourseCompletionEmail($payload['course_id'], $payload['user_id']);
      }
    }

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_mark_as_complete_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_mark_as_incomplete($request)
  {
    // 1) Pre-parameter filter
    $params = apply_filters('acadlix_pre_post_mark_as_incomplete_params', $request->get_params(), $request);

    $required_fields = ['course_id', 'course_section_content_id', 'user_id'];
    $errors = []; // FIXED: Initialized to prevent undefined variable errors

    foreach ($required_fields as $field) {
      $param = $params[$field] ?? $request->get_param($field) ?? null;

      if (empty($param)) {
        /* translators: %s is the required field */
        $errors[] = sprintf(__('The %s parameter is required.', 'acadlix'), $field);
      }
    }

    if (!empty($errors)) {
      return new WP_Error('missing_params', implode(' ', $errors), ['status' => 400]);
    }

    // 2) Payload Filter
    $payload = apply_filters('acadlix_post_mark_as_incomplete_payload', [
      'user_id' => intval($params['user_id'] ?? $request->get_param('user_id')),
      'course_id' => intval($params['course_id'] ?? $request->get_param('course_id')),
      'course_section_content_id' => intval($params['course_section_content_id'] ?? $request->get_param('course_section_content_id')),
    ], $params);

    $res = [
      'success' => true,
      'course_completion_percentage' => 0,
      'active_statistic' => null,
    ];

    $active_statistic = acadlix()->model()->courseStatistic()
      ->where('course_id', $payload['course_id'])
      ->where('course_section_content_id', $payload['course_section_content_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    $courseEnrollment = acadlix()
      ->model()
      ->courseEnrollment()
      ->where('course_id', $payload['course_id'])
      ->where('user_id', $payload['user_id'])
      ->first();

    if ($active_statistic) {
      $active_statistic->update(['is_completed' => false]);

      // 3a) Conditional Action: Updated existing statistic
      do_action('acadlix_post_mark_as_incomplete_updated', $active_statistic, $payload, $params);
    } else {
      $active_statistic = acadlix()->model()->courseStatistic()->create([
        'course_id' => $payload['course_id'],
        'course_section_content_id' => $payload['course_section_content_id'],
        'user_id' => $payload['user_id'],
        'is_active' => true,
        'is_completed' => false,
      ]);

      // 3b) Conditional Action: Created new statistic record
      do_action('acadlix_post_mark_as_incomplete_created', $active_statistic, $payload, $params);
    }

    $res['active_statistic'] = $active_statistic;
    // Save incomplete timestamp
    if ($active_statistic) {
      acadlix()->model()->userActivityMeta()->create([
        'user_id' => $payload['user_id'],
        'type' => 'course_statistic',
        'type_id' => $active_statistic->id,
        'meta_key' => 'course_statistic_incomplete_time',
        'meta_value' => time(),
      ]);
    }

    $course = acadlix()
      ->model()
      ->course()
      ->find($payload['course_id']);
    if ($course) {
      $course_completion_percentage = $course->getCourseCompletionPercentage($payload['user_id']) ?? 0;
      $courseEnrollment->update([
        'progress_percent' => $course_completion_percentage,
        'status' => $course_completion_percentage < 100 ? CourseEnrollment::STATUS_ACTIVE : CourseEnrollment::STATUS_COMPLETED,
      ]);
      $res['course_completion_percentage'] = $course_completion_percentage;
    }

    // 4) Outbound response filter
    $res = apply_filters('acadlix_post_mark_as_incomplete_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function get_user_purchases($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_purchases_params', $request->get_params(), $request);

    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? 0;
    if (empty($userId)) {
      return new WP_Error('no_data_found', __('Required user_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_purchases_payload', [
      'user_id' => intval($userId),
      'page' => intval($params['page'] ?? 0),
      'pageSize' => intval($params['pageSize'] ?? 10),
    ], $params);

    $skip = $payload['page'] * $payload['pageSize'];

    $orders = acadlix()->model()->order()
      ->with(['order_items', 'order_metas', 'user'])
      ->where('user_id', $payload['user_id'])
      ->orderBy('created_at', 'desc');

    $res = [
      'total' => $orders->count(),
      'orders' => $orders->skip($skip)->take($payload['pageSize'])->get(),
    ];

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_purchases', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_purchases_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function get_user_wishlist($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_wishlist_params', $request->get_params(), $request);

    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? 0;
    if (empty($userId)) {
      return new WP_Error('no_data_found', __('Required user_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_wishlist_payload', [
      'user_id' => intval($userId),
      'page' => intval($params['page'] ?? 0),
      'pageSize' => intval($params['pageSize'] ?? 10),
    ], $params);

    $skip = $payload['page'] * $payload['pageSize'];
    $wishlistQuery = acadlix()
      ->model()
      ->userActivityMeta()
      ->ofWishlist()
      ->where('user_id', $payload['user_id'])
      ->orderBy('created_at', 'desc');

    $res = [
      'total' => $wishlistQuery->count(),
      'wishlist' => $wishlistQuery
        ->skip($skip)
        ->take($payload['pageSize'])
        ->get()
        ->map(function ($item) {
          $resolved = $item->resolveWishlistItem();

          if ($resolved) {
            $item->item = $resolved['item'];
            $item->permalink = $resolved['permalink'];
          }
          return $item;
        }),
    ];

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_wishlist', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_wishlist_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function get_user_profile($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_profile_params', $request->get_params(), $request);

    $userId = $params['user_id'] ?? $request->get_param('user_id') ?? 0;
    if (empty($userId)) {
      return new WP_Error('no_data_found', __('Required user_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_profile_payload', [
      'user_id' => intval($userId),
    ], $params);

    $res = [
      'user' => acadlix()->model()->wpUsers()->with('user_metas')->where('ID', $payload['user_id'])->first(),
    ];

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_profile', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_profile_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_update_user_photo($request)
  {
    // 1) Pre-parameter filter
    $params = apply_filters('acadlix_pre_post_update_user_photo_params', $request->get_params(), $request);

    // Context Security: Fallback to the currently logged-in user if no ID is passed or if unauthorized
    $current_user_id = get_current_user_id();
    $target_user_id = intval($params['user_id'] ?? $request->get_param('user_id') ?? $current_user_id);

    // Authorization Guard: Prevent non-admins from changing other users' photos
    if ($target_user_id !== $current_user_id && !current_user_can('edit_users')) {
      return new WP_Error('rest_forbidden', __('You do not have permission to perform this action.', 'acadlix'), ['status' => 403]);
    }

    if ($target_user_id === 0) {
      return new WP_Error('missing_user_id', __('Valid user ID is required.', 'acadlix'), ['status' => 400]);
    }

    // Required core WordPress admin files for handling uploads
    if (!function_exists('wp_generate_attachment_metadata')) {
      require_once ABSPATH . 'wp-admin/includes/image.php';
    }
    if (!function_exists('wp_handle_upload')) {
      require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    if (!function_exists('wp_insert_attachment')) {
      require_once ABSPATH . 'wp-admin/includes/media.php';
    }

    $files = $request->get_file_params();
    if (empty($files['file'])) {
      return new WP_Error('no_file', __('No file uploaded', 'acadlix'), ['status' => 400]);
    }

    $file = $files['file'];

    $wp_filetype = wp_check_filetype($file['name'], null);
    $allowed_mimes = ['image/jpeg', 'image/png', 'image/jpg'];

    if (!in_array($wp_filetype['type'], $allowed_mimes, true)) {
      return new WP_Error('invalid_file_type', __('Only JPG and PNG files are allowed', 'acadlix'), ['status' => 400]);
    }

    // 2) Payload Filter
    $payload = apply_filters('acadlix_post_update_user_photo_payload', [
      'user_id' => $target_user_id,
      'file' => $file
    ], $params);

    $upload_overrides = ['test_form' => false];
    $uploaded_file = wp_handle_upload($payload['file'], $upload_overrides);

    if (isset($uploaded_file['error'])) {
      return new WP_Error('upload_error', $uploaded_file['error'], ['status' => 500]);
    }

    // Create attachment reference record
    $attachment_id = wp_insert_attachment([
      'guid' => $uploaded_file['url'],
      'post_mime_type' => $wp_filetype['type'],
      'post_title' => sanitize_file_name($payload['file']['name']),
      'post_content' => '',
      'post_status' => 'inherit'
    ], $uploaded_file['file']);

    if (is_wp_error($attachment_id) || !$attachment_id) {
      return new WP_Error('attachment_error', __('Failed to create attachment record.', 'acadlix'), ['status' => 500]);
    }

    // Generate downscaled imagery sizes and metadata profile
    $attachment_data = wp_generate_attachment_metadata($attachment_id, $uploaded_file['file']);
    wp_update_attachment_metadata($attachment_id, $attachment_data);

    $image_url = wp_get_attachment_url($attachment_id);

    // CLEANUP FIX: Delete the old profile picture attachment from storage to avoid bloating
    $old_attachment_id = get_user_meta($payload['user_id'], '_acadlix_profile_photo_id', true);
    if (!empty($old_attachment_id)) {
      wp_delete_attachment($old_attachment_id, true); // true forces bypass trash
    }

    // Keep records of both the URL and Attachment ID for easier meta querying
    update_user_meta($payload['user_id'], '_acadlix_profile_photo', $image_url);
    update_user_meta($payload['user_id'], '_acadlix_profile_photo_id', $attachment_id);

    // 3) Action Hooks
    do_action('acadlix_user_photo_updated', $payload['user_id'], $image_url, $attachment_id);

    $res = [
      'success' => true,
      'url' => $image_url,
    ];

    // 4) Outbound response filter
    $res = apply_filters('acadlix_post_update_user_photo_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_update_user_profile($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_update_user_profile_params', $request->get_json_params(), $request);

    $userId = $request->get_param('user_id');
    if (empty($userId)) {
      return new WP_Error('no_data_found', __('Required user_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_post_update_user_profile_payload', [
      'user_id' => intval($userId),
      'first_name' => sanitize_text_field($params['first_name'] ?? ''),
      'last_name' => sanitize_text_field($params['last_name'] ?? ''),
      'user_url' => sanitize_text_field($params['user_url'] ?? ''),
      'description' => sanitize_text_field($params['description'] ?? ''),
      'phonecode' => sanitize_text_field($params['phonecode'] ?? ''),
      'isocode' => sanitize_text_field($params['isocode'] ?? ''),
      'phone_number' => sanitize_text_field($params['phone_number'] ?? ''),
      'address' => sanitize_text_field($params['address'] ?? ''),
      'country' => sanitize_text_field($params['country'] ?? ''),
      'city' => sanitize_text_field($params['city'] ?? ''),
      'zip_code' => sanitize_text_field($params['zip_code'] ?? ''),
      'photo' => sanitize_text_field($params['photo'] ?? ''),
    ], $params);

    wp_update_user([
      'ID' => $payload['user_id'],
      'display_name' => trim($payload['first_name'] . ' ' . $payload['last_name']),
      'user_url' => $payload['user_url'],
    ]);

    update_user_meta($payload['user_id'], 'first_name', $payload['first_name']);
    update_user_meta($payload['user_id'], 'last_name', $payload['last_name']);
    update_user_meta($payload['user_id'], 'description', $payload['description']);
    update_user_meta($payload['user_id'], '_acadlix_profile_phonecode', $payload['phonecode']);
    update_user_meta($payload['user_id'], '_acadlix_profile_isocode', $payload['isocode']);
    update_user_meta($payload['user_id'], '_acadlix_profile_phone_number', $payload['phone_number']);
    update_user_meta($payload['user_id'], '_acadlix_profile_address', $payload['address']);
    update_user_meta($payload['user_id'], '_acadlix_profile_country', $payload['country']);
    update_user_meta($payload['user_id'], '_acadlix_profile_city', $payload['city']);
    update_user_meta($payload['user_id'], '_acadlix_profile_zip_code', $payload['zip_code']);
    // update_user_meta($payload['user_id'], '_acadlix_profile_photo', $payload['photo']);

    $res = [
      'user' => acadlix()->model()->wpUsers()->with('user_metas')->where('ID', $payload['user_id'])->first(),
    ];

    // 3) Lifecycle Action: allow listeners to react to the update
    do_action('acadlix_post_update_user_profile', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_update_user_profile_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function post_update_user_password($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_post_update_user_password_params', $request->get_json_params(), $request);

    $user = wp_get_current_user();
    if (!$user || !$user->ID) {
      return new WP_Error('no_user', __('User not found', 'acadlix'), array('status' => 404));
    }

    $payload = apply_filters('acadlix_post_update_user_password_payload', [
      'user_id' => $user->ID,
      'old_password' => sanitize_text_field($params['old_password'] ?? ''),
      'new_password' => sanitize_text_field($params['new_password'] ?? ''),
      'confirm_new_password' => sanitize_text_field($params['confirm_new_password'] ?? ''),
    ], $params);

    // Validate fields
    if (empty($payload['old_password']) || empty($payload['new_password']) || empty($payload['confirm_new_password'])) {
      return new WP_Error('missing_fields', __('All password fields are required', 'acadlix'), array('status' => 400));
    }

    // Check old password
    if (!wp_check_password($payload['old_password'], $user->user_pass, $user->ID)) {
      return new WP_Error('incorrect_old_password', __('Old password is incorrect', 'acadlix'), array('status' => 400));
    }

    // Check new password match
    if ($payload['new_password'] !== $payload['confirm_new_password']) {
      return new WP_Error('password_mismatch', __('Passwords do not match', 'acadlix'), array('status' => 400));
    }

    // Optional password strength validation
    if (strlen($payload['new_password']) < 8) {
      return new WP_Error('weak_password', __('Password must be at least 8 characters', 'acadlix'), array('status' => 400));
    }

    // Update password
    wp_set_password($payload['new_password'], $user->ID);

    // Re-login user (important)
    wp_set_auth_cookie($user->ID);

    $res = [
      'message' => __('Password updated successfully', 'acadlix'),
      'user' => acadlix()->model()->wpUsers()->with('user_metas')->where('ID', $user->ID)->first(),
    ];

    // 3) Lifecycle Action: allow listeners to react to the password update
    do_action('acadlix_post_update_user_password', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_post_update_user_password_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function get_user_certificate_by_id($request)
  {
    // 1) Pre-parameter filter: allow callers to mutate incoming params before validation
    $params = apply_filters('acadlix_pre_get_user_certificate_by_id_params', $request->get_params(), $request);

    $certificateId = $params['certificate_id'] ?? $request->get_param('certificate_id');
    if (empty($certificateId)) {
      return new WP_Error('no_data_found', __('Required certificate_id', 'acadlix'), array('status' => 404));
    }

    // 2) Payload/Data Filter: normalize values before core execution
    $payload = apply_filters('acadlix_get_user_certificate_by_id_payload', [
      'certificate_id' => sanitize_text_field($certificateId),
    ], $params);

    $certificate = acadlix()
      ->model()
      ->userActivityMeta()
      ->ofCertificate()
      ->where('reference_id', $payload['certificate_id'])
      ->first();

    if (!$certificate) {
      return new WP_Error('no_data_found', __('Certificate not found', 'acadlix'), array('status' => 404));
    }

    $res = ['certificate' => $certificate];

    // 3) Lifecycle Action: allow listeners to react to the fetch
    do_action('acadlix_get_user_certificate_by_id', $res, $payload, $params);

    // 4) Outbound Response Filter: allow other modules to modify the response
    $res = apply_filters('acadlix_get_user_certificate_by_id_response', $res, $payload, $params);

    return rest_ensure_response($res);
  }

  public function check_permission($request)
  {
    if (!is_user_logged_in()) {
      return new WP_Error('not_logged_in', 'Login required', ['status' => 401]);
    }

    $user_id = absint($request->get_param('user_id') ?? 0);

    if ($user_id && get_current_user_id() !== $user_id) {
      return new WP_Error('forbidden', 'Access denied', ['status' => 403]);
    }

    return true;
  }
}
