<?php
/**
 * Frontend singular guard for restricted content.
 *
 * @package Polanger_Dashboard_Tools
 */

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

class PDT_Content_Visibility_Guard {

  /**
   * Soft-denied post ID for the current request.
   *
   * @var int
   */
  private $soft_denied_post_id = 0;

  /**
   * Register frontend hooks.
   *
   * @return void
   */
  public function register_hooks() {
    add_action( 'template_redirect', array( $this, 'guard_singular_request' ), 1 );
    add_filter( 'the_content', array( $this, 'filter_restricted_content' ), 9999 );
    add_filter( 'get_the_excerpt', array( $this, 'filter_restricted_excerpt' ), 20, 2 );
    add_filter( 'post_thumbnail_html', array( $this, 'filter_restricted_featured_image' ), 20, 5 );
    add_filter( 'the_title', array( $this, 'filter_restricted_title' ), 20, 2 );
    add_filter( 'document_title_parts', array( $this, 'filter_document_title_parts' ) );
  }

  /**
   * Guard direct frontend access to singular restricted content.
   *
   * @return void
   */
  public function guard_singular_request() {
    if ( is_admin() || wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
      return;
    }

    if ( ! is_singular() ) {
      return;
    }

    $post_id = absint( get_queried_object_id() );

    if ( ! $post_id || ! PDT_Content_Visibility::is_supported_post( $post_id ) ) {
      return;
    }

    if ( PDT_Content_Visibility::current_user_can_preview_post( $post_id ) ) {
      return;
    }

    if ( PDT_Content_Visibility::can_user_view_post( $post_id ) ) {
      return;
    }

    $behavior = PDT_Content_Visibility::resolve_denied_behavior( $post_id );

    if ( 'login' === $behavior && is_user_logged_in() ) {
      $behavior = 'message';
    }

    if ( 'custom_redirect' === $behavior ) {
      wp_safe_redirect( PDT_Content_Visibility::resolve_redirect_url( $post_id ) );
      exit;
    }

    if ( 'login' === $behavior ) {
      wp_safe_redirect( wp_login_url( get_permalink( $post_id ) ) );
      exit;
    }

    if ( '404' === $behavior ) {
      $this->render_404();
    }

    $compatibility = PDT_Content_Visibility::resolve_compatibility_mode( $post_id );
    nocache_headers();

    if ( 'hard' === $compatibility ) {
      status_header( 403 );
      $this->enqueue_frontend_style();
      $this->render_hard_template( $post_id );
    }

    status_header( 403 );
    $this->soft_denied_post_id = $post_id;
    $this->enqueue_frontend_style();
  }

  /**
   * Replace the main content output for theme-friendly mode.
   *
   * @param string $content Original content.
   * @return string
   */
  public function filter_restricted_content( $content ) {
    if ( ! $this->is_soft_denied_loop_context() ) {
      return $content;
    }

    return PDT_Content_Visibility::render_access_denied_notice( $this->soft_denied_post_id );
  }

  /**
   * Mask excerpts for the denied singular post in soft mode.
   *
   * @param string       $excerpt Current excerpt.
   * @param WP_Post|null $post    Post object when available.
   * @return string
   */
  public function filter_restricted_excerpt( $excerpt, $post = null ) {
    if ( ! $this->is_soft_denied_request() ) {
      return $excerpt;
    }

    $post_id = $post instanceof WP_Post ? absint( $post->ID ) : absint( get_the_ID() );

    if ( $post_id !== $this->soft_denied_post_id ) {
      return $excerpt;
    }

    return __( 'This content is protected.', 'polanger-admin-menu-manager' );
  }

  /**
   * Hide the featured image for the denied singular post in soft mode.
   *
   * @param string       $html              Current image HTML.
   * @param int          $post_id           Post ID.
   * @param int          $post_thumbnail_id Attachment ID.
   * @param string|array $size              Requested size.
   * @param string|array $attr              Extra attributes.
   * @return string
   */
  public function filter_restricted_featured_image( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
    unset( $post_thumbnail_id, $size, $attr );

    if ( ! $this->is_soft_denied_request() ) {
      return $html;
    }

    return absint( $post_id ) === $this->soft_denied_post_id ? '' : $html;
  }

  /**
   * Mask the visible post title during soft-denied requests.
   *
   * @param string $title   Current title.
   * @param int    $post_id Post ID.
   * @return string
   */
  public function filter_restricted_title( $title, $post_id ) {
    $post_id = absint( $post_id );

    if ( ! $this->is_soft_denied_request() || ! in_the_loop() || ! is_main_query() ) {
      return $title;
    }

    if ( $post_id !== $this->soft_denied_post_id ) {
      return $title;
    }

    return __( 'Access Restricted', 'polanger-admin-menu-manager' );
  }

  /**
   * Mask the browser title during soft-denied requests.
   *
   * @param array $parts Title parts.
   * @return array
   */
  public function filter_document_title_parts( $parts ) {
    if ( ! $this->is_soft_denied_request() || ! is_array( $parts ) ) {
      return $parts;
    }

    $parts['title'] = __( 'Access Restricted', 'polanger-admin-menu-manager' );

    return $parts;
  }

  /**
   * Whether the current loop output should be replaced.
   *
   * @return bool
   */
  private function is_soft_denied_loop_context() {
    if ( ! $this->is_soft_denied_request() ) {
      return false;
    }

    if ( ! is_singular() || ! in_the_loop() || ! is_main_query() ) {
      return false;
    }

    return absint( get_the_ID() ) === $this->soft_denied_post_id;
  }

  /**
   * Whether this request is currently soft-blocked.
   *
   * @return bool
   */
  private function is_soft_denied_request() {
    return $this->soft_denied_post_id > 0;
  }

  /**
   * Load the shared frontend stylesheet.
   *
   * @return void
   */
  private function enqueue_frontend_style() {
    wp_enqueue_style(
      'pdt-content-visibility-front',
      plugins_url( 'assets/css/content-visibility-front.css', PDT_PLUGIN_FILE ),
      array(),
      PDT_VERSION
    );
  }

  /**
   * Render the full override access denied template.
   *
   * @param int $post_id Post ID.
   * @return void
   */
  private function render_hard_template( $post_id ) {
    $pdt_content_visibility_context = PDT_Content_Visibility::get_access_denied_context( $post_id );

    include PDT_PLUGIN_DIR . 'templates/access-denied.php';
    exit;
  }

  /**
   * Render the plugin-owned protected 404 template.
   *
   * @return void
   */
  private function render_404() {
    global $wp_query;

    if ( ! $wp_query instanceof WP_Query ) {
      $wp_query = new WP_Query();
    }

    $wp_query->set_404();
    status_header( 404 );
    nocache_headers();

    wp_enqueue_style(
      'pdt-login-guard-404',
      plugins_url( 'assets/css/login-guard-404.css', PDT_PLUGIN_FILE ),
      array(),
      PDT_VERSION
    );

    $pdt_login_guard_404_context = $this->get_protected_404_context();

    include PDT_PLUGIN_DIR . 'templates/login-guard-404.php';
    exit;
  }

  /**
   * Build the context used by the protected 404 template.
   *
   * @return array<string,string>
   */
  private function get_protected_404_context() {
    $login_settings   = get_option( 'pdt_login_page_settings', array() );
    $site_title       = wp_strip_all_tags( get_bloginfo( 'name' ), true );
    $site_icon_url    = get_site_icon_url( 192 );
    $custom_logo_url  = ! empty( $login_settings['custom_logo_url'] ) ? esc_url_raw( $login_settings['custom_logo_url'] ) : '';

    return array(
      'page_title'      => sprintf(
        /* translators: %s: Site title. */
        __( 'Page not found - %s', 'polanger-admin-menu-manager' ),
        $site_title
      ),
      'eyebrow'         => '',
      'title'           => __( 'Looks like we wandered off the map.', 'polanger-admin-menu-manager' ),
      'message'         => __( 'We could not find the address you were looking for, but that does not mean the road ends here.', 'polanger-admin-menu-manager' ),
      'supporting_text' => __( 'There may be a typo, or the page may have been updated. We will guide you back to a safe path right away. Use the link below to return to the homepage.', 'polanger-admin-menu-manager' ),
      'home_label'      => __( 'Return to homepage', 'polanger-admin-menu-manager' ),
      'home_url'        => home_url( '/' ),
      'site_title'      => $site_title,
      'site_icon_url'   => $site_icon_url ? esc_url_raw( $site_icon_url ) : '',
      'logo_url'        => $custom_logo_url,
      'body_style'      => '',
    );
  }
}
