<?php
/**
 * Admin Activity Log Addon
 * 
 * Logs administrative actions for security and auditing purposes.
 * GDPR/KVKK compliant - no personal or content data is stored.
 *
 * @package Polanger_WP_Admin_Menu_Manager_Pro
 * @subpackage Addons
 * @since 1.1.0
 */

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

class PDT_Admin_Activity_Log {

  /**
   * Database table name
   */
  private $table_name;

  /**
   * Settings option name
   */
  private $option_name = 'pdt_activity_log_settings';

  /**
   * Default settings
   */
  private $default_settings = array(
    'enabled'           => false,
    'log_ip'            => false,
    'retention_days'    => 30,
    'log_logins'        => true,
    'log_security'      => true,
    'log_plugins'       => true,
    'log_themes'        => true,
    'log_posts'         => true,
    'log_users'         => true,
    'log_system'        => true,
    'log_settings'      => true,
    'log_menus'         => true,
    'email_alerts'      => false,
    'alert_email'       => '',
    'critical_actions'  => array( 'user_deleted', 'user_role_changed', 'plugin_deleted', 'siteurl_changed', 'home_url_changed', 'admin_email_changed', 'password_changed' ),
  );

  /**
   * Event severity levels
   */
  private $event_severity = array(
    // Critical (Red) - Security sensitive, potential hack indicators
    'siteurl_changed'       => 'critical',
    'home_url_changed'      => 'critical',
    'admin_email_changed'   => 'critical',
    'user_deleted'          => 'critical',
    'user_role_changed'     => 'critical',
    'plugin_deleted'        => 'critical',
    'password_changed'      => 'critical',
    // Warning (Orange) - Attention needed
    'login_failed'          => 'warning',
    'password_reset_requested' => 'warning',
    'plugin_deactivated'    => 'warning',
    'theme_switched'        => 'warning',
    'permalink_changed'     => 'warning',
    // Info (Blue) - default for all others
  );

  /**
   * Constructor
   */
  public function __construct() {
    global $wpdb;
    $this->table_name = $wpdb->prefix . 'pdt_admin_logs';

    // Register activation hook for table creation
    add_action( 'admin_init', array( $this, 'maybe_create_table' ) );
    
    // Handle CSV export early (before headers are sent)
    add_action( 'admin_init', array( $this, 'handle_csv_export' ) );
    
    // Handle clear logs early (before headers are sent)
    add_action( 'admin_init', array( $this, 'handle_clear_logs' ) );
    add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );

    // Only hook if logging is enabled
    if ( $this->is_enabled() ) {
      $this->register_hooks();
    }

    // Public ingestion hook so any addon can record an event without holding
    // a reference to this object. Registered unconditionally; log() itself
    // bails when logging is disabled.
    add_action( 'pdt_log_activity', array( $this, 'log_external_event' ), 10, 1 );

    // Cleanup cron
    add_action( 'pdt_cleanup_old_logs', array( $this, 'cleanup_old_logs' ) );
    
    if ( ! wp_next_scheduled( 'pdt_cleanup_old_logs' ) ) {
      wp_schedule_event( time(), 'daily', 'pdt_cleanup_old_logs' );
    }
  }

  /**
   * Enqueue addon assets for activity log page.
   *
   * @return void
   */
  public function enqueue_assets() {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
    if ( 'polanger-activity-log' !== $page ) {
      return;
    }

    wp_enqueue_script(
      'pdt-activity-log-script',
      plugin_dir_url( __FILE__ ) . 'js/activity-log.js',
      array( 'jquery' ),
      PDT_VERSION,
      true
    );
  }

  /**
   * Check if logging is enabled
   */
  public function is_enabled() {
    $settings = $this->get_settings();
    return ! empty( $settings['enabled'] );
  }

  /**
   * Get settings
   */
  public function get_settings() {
    $settings = get_option( $this->option_name, array() );
    $settings = wp_parse_args( $settings, $this->default_settings );

    return apply_filters( 'polanger_effective_settings', $settings, $this->option_name, $this->default_settings, 'activity-log' );
  }

  /**
   * Get main plugin general settings.
   *
   * @return array
   */
  private function get_general_settings() {
    $defaults = array(
      'log_visibility'        => 'all',
      'email_alert_threshold' => 'disabled',
    );
    $settings = get_option( 'pdt_general_settings', array() );
    $settings = wp_parse_args( is_array( $settings ) ? $settings : array(), $defaults );

    return apply_filters( 'polanger_effective_settings', $settings, 'pdt_general_settings', $defaults, 'activity-log-general' );
  }

  /**
   * Get protected admin fallback user ID.
   *
   * @return int
   */
  private function get_fallback_protected_admin_id() {
    if ( is_multisite() ) {
      $super_admins = get_super_admins();
      if ( ! empty( $super_admins ) ) {
        $super_admin = get_user_by( 'login', $super_admins[0] );
        if ( $super_admin ) {
          return (int) $super_admin->ID;
        }
      }
    }

    $admins = get_users(
      array(
        'role'    => 'administrator',
        'orderby' => 'ID',
        'order'   => 'ASC',
        'number'  => 1,
        'fields'  => array( 'ID' ),
      )
    );

    if ( ! empty( $admins ) && isset( $admins[0]->ID ) ) {
      return (int) $admins[0]->ID;
    }

    return (int) get_current_user_id();
  }

  /**
   * Determine whether a user is protected admin.
   *
   * @param int $user_id User ID.
   * @return bool
   */
  private function is_protected_admin_user( $user_id ) {
    $user_id = absint( $user_id );
    if ( ! $user_id ) {
      return false;
    }

    if ( is_multisite() ) {
      return is_super_admin( $user_id );
    }

    return $user_id === $this->get_fallback_protected_admin_id();
  }

  /**
   * Check whether current user can view logs.
   *
   * @return bool
   */
  private function can_current_user_view_logs() {
    if ( ! current_user_can( 'manage_options' ) ) {
      return false;
    }

    $general_settings = $this->get_general_settings();
    $log_visibility = isset( $general_settings['log_visibility'] ) ? $general_settings['log_visibility'] : 'all';

    if ( 'super_admin' === $log_visibility ) {
      return $this->is_protected_admin_user( get_current_user_id() );
    }

    return true;
  }

  /**
   * Check if an action should trigger email based on severity threshold.
   *
   * @param string $action Action name.
   * @return bool
   */
  private function should_send_email_alert_for_action( $action ) {
    $addon_settings = $this->get_settings();
    if ( empty( $addon_settings['email_alerts'] ) ) {
      return false;
    }

    $general_settings = $this->get_general_settings();
    $threshold = isset( $general_settings['email_alert_threshold'] ) ? $general_settings['email_alert_threshold'] : 'disabled';
    $threshold = in_array( $threshold, array( 'disabled', 'critical', 'warning' ), true ) ? $threshold : 'disabled';

    if ( 'disabled' === $threshold ) {
      return false;
    }

    $severity = $this->get_action_severity( $action );

    if ( 'critical' === $threshold ) {
      return 'critical' === $severity;
    }

    return in_array( $severity, array( 'critical', 'warning' ), true );
  }

  /**
   * Update settings
   */
  public function update_settings( $new_settings ) {
    $settings = wp_parse_args( $new_settings, $this->default_settings );
    update_option( $this->option_name, $settings );
  }

  /**
   * Create database table if not exists
   */
  public function maybe_create_table() {
    global $wpdb;

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Table existence check during initialization.
    $table_exists = $wpdb->get_var( $wpdb->prepare( 
      "SHOW TABLES LIKE %s", 
      $this->table_name 
    ) );

    if ( $table_exists !== $this->table_name ) {
      $this->create_table();
    }
  }

  /**
   * Create the logs table
   */
  private function create_table() {
    global $wpdb;

    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE {$this->table_name} (
      id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      user_id bigint(20) unsigned NOT NULL,
      user_login varchar(60) NOT NULL,
      action varchar(100) NOT NULL,
      object_type varchar(50) DEFAULT NULL,
      object_id bigint(20) unsigned DEFAULT NULL,
      object_name varchar(255) DEFAULT NULL,
      ip_address varchar(45) DEFAULT NULL,
      user_agent varchar(255) DEFAULT NULL,
      meta longtext DEFAULT NULL,
      created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      PRIMARY KEY (id),
      KEY user_id (user_id),
      KEY action (action),
      KEY object_type (object_type),
      KEY created_at (created_at)
    ) $charset_collate;";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta( $sql );
  }

  /**
   * Register all hooks for logging
   */
  private function register_hooks() {
    $settings = $this->get_settings();

    // Login/Logout
    if ( ! empty( $settings['log_logins'] ) ) {
      add_action( 'wp_login', array( $this, 'log_login' ), 10, 2 );
      add_action( 'wp_logout', array( $this, 'log_logout' ) );
      add_action( 'wp_login_failed', array( $this, 'log_login_failed' ) );
    }

    // Plugins
    if ( ! empty( $settings['log_plugins'] ) ) {
      add_action( 'activated_plugin', array( $this, 'log_plugin_activated' ), 10, 2 );
      add_action( 'deactivated_plugin', array( $this, 'log_plugin_deactivated' ), 10, 2 );
      add_action( 'deleted_plugin', array( $this, 'log_plugin_deleted' ), 10, 2 );
      add_action( 'upgrader_process_complete', array( $this, 'log_plugin_updated' ), 10, 2 );
    }

    // Themes
    if ( ! empty( $settings['log_themes'] ) ) {
      add_action( 'switch_theme', array( $this, 'log_theme_switched' ), 10, 3 );
    }

    // Posts/Pages
    if ( ! empty( $settings['log_posts'] ) ) {
      add_action( 'save_post', array( $this, 'log_post_saved' ), 10, 3 );
      add_action( 'before_delete_post', array( $this, 'log_post_deleted' ) );
      add_action( 'trashed_post', array( $this, 'log_post_trashed' ) );
    }

    // Users
    if ( ! empty( $settings['log_users'] ) ) {
      add_action( 'user_register', array( $this, 'log_user_registered' ) );
      add_action( 'delete_user', array( $this, 'log_user_deleted' ), 10, 2 );
      add_action( 'set_user_role', array( $this, 'log_user_role_changed' ), 10, 3 );
    }

    // Settings (our plugin settings)
    if ( ! empty( $settings['log_settings'] ) ) {
      add_action( 'update_option_pdt_settings', array( $this, 'log_pdt_settings_changed' ), 10, 2 );
    }

    // Menu changes (our plugin)
    if ( ! empty( $settings['log_menus'] ) ) {
      add_action( 'update_option_pdt_menu_items', array( $this, 'log_menu_items_changed' ), 10, 2 );
    }

    // Security events
    if ( ! empty( $settings['log_security'] ) ) {
      add_action( 'after_password_reset', array( $this, 'log_password_changed' ), 10, 2 );
      add_action( 'profile_update', array( $this, 'log_password_changed_profile' ), 10, 2 );
      add_action( 'retrieve_password', array( $this, 'log_password_reset_requested' ) );
    }

    // System events
    if ( ! empty( $settings['log_system'] ) ) {
      add_action( 'update_option_siteurl', array( $this, 'log_siteurl_changed' ), 10, 2 );
      add_action( 'update_option_home', array( $this, 'log_home_url_changed' ), 10, 2 );
      add_action( 'update_option_admin_email', array( $this, 'log_admin_email_changed' ), 10, 2 );
      add_action( 'update_option_permalink_structure', array( $this, 'log_permalink_changed' ), 10, 2 );
    }

    // Theme customizer
    if ( ! empty( $settings['log_themes'] ) ) {
      add_action( 'customize_save_after', array( $this, 'log_customizer_saved' ) );
    }
  }

  /**
   * Record an event arriving through the public `pdt_log_activity` action.
   *
   * Lets external addons log to the activity table via a decoupled hook:
   *   do_action( 'pdt_log_activity', array(
   *     'action'      => 'shield_rule_created',
   *     'object_type' => 'shield_rule',
   *     'object_id'   => 123,
   *     'object_name' => 'WooCommerce Orders',
   *     'meta'        => array( 'severity' => 'warning' ),
   *   ) );
   *
   * @param array $args Event arguments.
   * @return void
   */
  public function log_external_event( $args ) {
    if ( ! is_array( $args ) ) {
      return;
    }

    $action = isset( $args['action'] ) ? sanitize_text_field( $args['action'] ) : '';
    if ( '' === $action ) {
      return;
    }

    $this->log(
      $action,
      isset( $args['object_type'] ) ? $args['object_type'] : null,
      isset( $args['object_id'] ) ? $args['object_id'] : null,
      isset( $args['object_name'] ) ? $args['object_name'] : null,
      ( isset( $args['meta'] ) && is_array( $args['meta'] ) ) ? $args['meta'] : array()
    );
  }

  /**
   * Log an action
   */
  public function log( $action, $object_type = null, $object_id = null, $object_name = null, $meta = array() ) {
    global $wpdb;

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

    $user = wp_get_current_user();
    $settings = $this->get_settings();

    $data = array(
      'user_id'     => $user->ID,
      'user_login'  => $user->user_login ? $user->user_login : 'guest',
      'action'      => sanitize_text_field( $action ),
      'object_type' => $object_type ? sanitize_text_field( $object_type ) : null,
      'object_id'   => $object_id ? absint( $object_id ) : null,
      'object_name' => $object_name ? sanitize_text_field( $object_name ) : null,
      'meta'        => ! empty( $meta ) ? wp_json_encode( $meta ) : null,
      'created_at'  => current_time( 'mysql' ),
    );

    // IP address (optional, GDPR compliant)
    if ( ! empty( $settings['log_ip'] ) ) {
      $data['ip_address'] = $this->get_client_ip();
    }

    // User agent (truncated)
    if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
      $data['user_agent'] = substr( sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ), 0, 255 );
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Logging requires direct insert to custom table.
    $wpdb->insert( $this->table_name, $data );

    // Send email alert based on configured global threshold.
    if ( $this->should_send_email_alert_for_action( $action ) ) {
      $this->send_alert_email( $data );
    }
  }

  /**
   * Get client IP address (anonymized option available)
   */
  private function get_client_ip() {
    $remote_addr = '';
    if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
      $remote_addr = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
      if ( filter_var( $remote_addr, FILTER_VALIDATE_IP ) ) {
        // Default-safe behavior: trust REMOTE_ADDR unless known trusted proxy is configured.
        if ( ! $this->is_trusted_proxy( $remote_addr ) ) {
          return $remote_addr;
        }
      } else {
        $remote_addr = '';
      }
    }

    // When request comes through a trusted proxy, use forwarded headers cautiously.
    $ip_candidates = array();

    if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
      $forwarded_for = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
      $ip_candidates = array_merge( $ip_candidates, array_map( 'trim', explode( ',', $forwarded_for ) ) );
    }

    if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
      $ip_candidates[] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) );
    }

    foreach ( $ip_candidates as $candidate ) {
      if ( filter_var( $candidate, FILTER_VALIDATE_IP ) ) {
        return $candidate;
      }
    }

    return $remote_addr;
  }

  /**
   * Check whether request originates from a trusted proxy.
   *
   * Site owners can define trusted proxy IPs via filter.
   *
   * @param string $remote_addr Request REMOTE_ADDR.
   * @return bool
   */
  private function is_trusted_proxy( $remote_addr ) {
    $trusted_proxies = apply_filters( 'pdt_activity_log_trusted_proxies', array() );
    if ( ! is_array( $trusted_proxies ) ) {
      return false;
    }

    $trusted_proxies = array_map( 'trim', $trusted_proxies );
    return in_array( $remote_addr, $trusted_proxies, true );
  }

  /**
   * Send alert email
   */
  private function send_alert_email( $log_data ) {
    $settings = $this->get_settings();
    $to = ! empty( $settings['alert_email'] ) ? $settings['alert_email'] : get_option( 'admin_email' );

    $subject = sprintf(
      /* translators: %s: site name */
      __( '[%s] Critical Admin Action Alert', 'polanger-admin-menu-manager' ),
      get_bloginfo( 'name' )
    );

    $message = sprintf(
      /* translators: 1: Action label, 2: Username, 3: Object name, 4: Event datetime. */
      __( "A critical action was performed on your site:\n\nAction: %1\$s\nUser: %2\$s\nObject: %3\$s\nTime: %4\$s\n\nThis is an automated security alert.", 'polanger-admin-menu-manager' ),
      $log_data['action'],
      $log_data['user_login'],
      $log_data['object_name'] ? $log_data['object_name'] : 'N/A',
      $log_data['created_at']
    );

    wp_mail( $to, $subject, $message );
  }

  // ========================================
  // LOGIN/LOGOUT HOOKS
  // ========================================

  public function log_login( $user_login, $user ) {
    $this->log( 'user_login', 'user', $user->ID, $user_login );
  }

  public function log_logout() {
    $user = wp_get_current_user();
    $this->log( 'user_logout', 'user', $user->ID, $user->user_login );
  }

  public function log_login_failed( $username ) {
    // Rate limiting: Group failed logins from same IP within 10 minutes
    $settings = $this->get_settings();
    $ip = $settings['log_ip'] ? $this->get_client_ip() : 'unknown';
    $transient_key = 'pdt_failed_login_' . md5( $ip );
    
    $recent_attempts = get_transient( $transient_key );
    
    if ( $recent_attempts ) {
      // Update count instead of creating new log
      $recent_attempts['count']++;
      set_transient( $transient_key, $recent_attempts, 10 * MINUTE_IN_SECONDS );
      
      // Update existing log entry with new count
      global $wpdb;
      // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Updating existing aggregated failed-login row.
      $wpdb->update(
        $this->table_name,
        array( 'meta' => maybe_serialize( array( 'attempts' => $recent_attempts['count'] ) ) ),
        array( 'id' => $recent_attempts['log_id'] ),
        array( '%s' ),
        array( '%d' )
      );
      return;
    }
    
    // First attempt - create new log
    $this->log( 'login_failed', 'security', null, 'Failed login attempt', array( 'attempts' => 1 ) );
    
    // Get the last inserted log ID
    global $wpdb;
    $log_id = $wpdb->insert_id;
    
    // Store in transient for rate limiting
    set_transient( $transient_key, array(
      'log_id' => $log_id,
      'count'  => 1,
    ), 10 * MINUTE_IN_SECONDS );
  }

  // ========================================
  // PLUGIN HOOKS
  // ========================================

  public function log_plugin_activated( $plugin, $network_wide ) {
    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
    $this->log( 'plugin_activated', 'plugin', null, $plugin_data['Name'], array( 'file' => $plugin ) );
  }

  public function log_plugin_deactivated( $plugin, $network_wide ) {
    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
    $this->log( 'plugin_deactivated', 'plugin', null, $plugin_data['Name'], array( 'file' => $plugin ) );
  }

  public function log_plugin_deleted( $plugin, $deleted ) {
    if ( $deleted ) {
      $this->log( 'plugin_deleted', 'plugin', null, $plugin );
    }
  }

  public function log_plugin_updated( $upgrader, $options ) {
    if ( $options['type'] === 'plugin' && $options['action'] === 'update' ) {
      if ( isset( $options['plugins'] ) ) {
        foreach ( $options['plugins'] as $plugin ) {
          $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
          $this->log( 'plugin_updated', 'plugin', null, $plugin_data['Name'], array(
            'new_version' => $plugin_data['Version'],
          ) );
        }
      }
    }
  }

  // ========================================
  // THEME HOOKS
  // ========================================

  public function log_theme_switched( $new_name, $new_theme, $old_theme ) {
    $this->log( 'theme_switched', 'theme', null, $new_name, array( 
      'old_theme' => $old_theme->get( 'Name' ) 
    ) );
  }

  // ========================================
  // POST HOOKS
  // ========================================

  public function log_post_saved( $post_id, $post, $update ) {
    // Skip autosaves and revisions
    if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
      return;
    }

    // Skip if not admin
    if ( ! is_admin() ) {
      return;
    }

    $action = $update ? 'post_updated' : 'post_created';
    $this->log( $action, $post->post_type, $post_id, $post->post_title );
  }

  public function log_post_deleted( $post_id ) {
    $post = get_post( $post_id );
    if ( $post ) {
      $this->log( 'post_deleted', $post->post_type, $post_id, $post->post_title );
    }
  }

  public function log_post_trashed( $post_id ) {
    $post = get_post( $post_id );
    if ( $post ) {
      $this->log( 'post_trashed', $post->post_type, $post_id, $post->post_title );
    }
  }

  // ========================================
  // USER HOOKS
  // ========================================

  public function log_user_registered( $user_id ) {
    $user = get_userdata( $user_id );
    $this->log( 'user_created', 'user', $user_id, $user->user_login );
  }

  public function log_user_deleted( $user_id, $reassign ) {
    $user = get_userdata( $user_id );
    $username = $user ? $user->user_login : "User #$user_id";
    $this->log( 'user_deleted', 'user', $user_id, $username );
  }

  public function log_user_role_changed( $user_id, $role, $old_roles ) {
    $user = get_userdata( $user_id );
    $this->log( 'user_role_changed', 'user', $user_id, $user->user_login, array(
      'new_role'  => $role,
      'old_roles' => $old_roles,
    ) );
  }

  // ========================================
  // SETTINGS HOOKS
  // ========================================

  public function log_pdt_settings_changed( $old_value, $new_value ) {
    $this->log( 'pdt_settings_changed', 'setting', null, 'pdt_settings' );
  }

  public function log_menu_items_changed( $old_value, $new_value ) {
    $this->log( 'menu_items_updated', 'setting', null, 'pdt_menu_items' );
  }

  // ========================================
  // SECURITY HOOKS
  // ========================================

  public function log_password_changed( $user, $new_pass ) {
    $this->log( 'password_changed', 'user', $user->ID, "User #{$user->ID}" );
  }

  public function log_password_changed_profile( $user_id, $old_user_data ) {
    $user = get_userdata( $user_id );
    if ( $user && isset( $old_user_data->user_pass ) && $user->user_pass !== $old_user_data->user_pass ) {
      $this->log( 'password_changed', 'user', $user_id, "User #{$user_id}" );
    }
  }

  public function log_password_reset_requested( $user_login ) {
    $this->log( 'password_reset_requested', 'security', null, 'Password reset' );
  }

  // ========================================
  // SYSTEM HOOKS
  // ========================================

  public function log_siteurl_changed( $old_value, $new_value ) {
    if ( $old_value !== $new_value ) {
      $this->log( 'siteurl_changed', 'system', null, 'Site URL', array(
        'old' => $old_value,
        'new' => $new_value,
      ) );
    }
  }

  public function log_home_url_changed( $old_value, $new_value ) {
    if ( $old_value !== $new_value ) {
      $this->log( 'home_url_changed', 'system', null, 'Home URL', array(
        'old' => $old_value,
        'new' => $new_value,
      ) );
    }
  }

  public function log_admin_email_changed( $old_value, $new_value ) {
    if ( $old_value !== $new_value ) {
      $this->log( 'admin_email_changed', 'system', null, 'Admin Email' );
    }
  }

  public function log_permalink_changed( $old_value, $new_value ) {
    if ( $old_value !== $new_value ) {
      $this->log( 'permalink_changed', 'system', null, 'Permalink Structure' );
    }
  }

  public function log_customizer_saved( $wp_customize ) {
    $this->log( 'customizer_saved', 'theme', null, 'Theme Customizer' );
  }

  // ========================================
  // LOG RETRIEVAL
  // ========================================

  /**
   * Get logs with pagination and filters
   */
  public function get_logs( $args = array() ) {
    global $wpdb;

    $defaults = array(
      'per_page'    => 20,
      'page'        => 1,
      'user_id'     => null,
      'action'      => null,
      'object_type' => null,
      'date_from'   => null,
      'date_to'     => null,
      'search'      => null,
      'orderby'     => 'created_at',
      'order'       => 'DESC',
    );

    $args = wp_parse_args( $args, $defaults );

    $where = array( '1=1' );
    $values = array();

    if ( $args['user_id'] ) {
      $where[] = 'user_id = %d';
      $values[] = $args['user_id'];
    }

    if ( $args['action'] ) {
      $where[] = 'action = %s';
      $values[] = $args['action'];
    }

    if ( $args['object_type'] ) {
      $where[] = 'object_type = %s';
      $values[] = $args['object_type'];
    }

    if ( $args['date_from'] ) {
      $where[] = 'created_at >= %s';
      $values[] = $args['date_from'] . ' 00:00:00';
    }

    if ( $args['date_to'] ) {
      $where[] = 'created_at <= %s';
      $values[] = $args['date_to'] . ' 23:59:59';
    }

    if ( $args['search'] ) {
      $where[] = '(user_login LIKE %s OR object_name LIKE %s OR action LIKE %s)';
      $search = '%' . $wpdb->esc_like( $args['search'] ) . '%';
      $values[] = $search;
      $values[] = $search;
      $values[] = $search;
    }

    $where_sql = implode( ' AND ', $where );
    $table_name = $this->get_safe_table_name();
    $orderby = $this->build_safe_orderby( $args['orderby'], $args['order'] );
    $offset = ( $args['page'] - 1 ) * $args['per_page'];

    // Get total count.
    if ( ! empty( $values ) ) {
      // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- WHERE fragments are fixed templates; only values are user-provided and prepared.
      $total = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE {$where_sql}", ...$values ) );
    } else {
      // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- WHERE is built from fixed templates and contains no user values in this branch.
      $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table_name} WHERE {$where_sql}" );
    }

    // Get results.
    $values[] = $args['per_page'];
    $values[] = $offset;
    
    // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- WHERE is built from fixed clauses; ORDER BY is sanitized via sanitize_sql_orderby.
    $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE {$where_sql} ORDER BY {$orderby} LIMIT %d OFFSET %d", ...$values ) );

    return array(
      'logs'       => $results,
      'total'      => (int) $total,
      'pages'      => ceil( $total / $args['per_page'] ),
      'page'       => $args['page'],
      'per_page'   => $args['per_page'],
    );
  }

  /**
   * Get unique actions for filter dropdown
   */
  public function get_unique_actions() {
    global $wpdb;
    $table_name = $this->get_safe_table_name();
    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Distinct options loaded from custom log table.
    return $wpdb->get_col( "SELECT DISTINCT action FROM {$table_name} ORDER BY action" );
  }

  /**
   * Get unique object types for filter dropdown
   */
  public function get_unique_object_types() {
    global $wpdb;
    $table_name = $this->get_safe_table_name();
    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Distinct options loaded from custom log table.
    return $wpdb->get_col( "SELECT DISTINCT object_type FROM {$table_name} WHERE object_type IS NOT NULL ORDER BY object_type" );
  }

  /**
   * Build safe ORDER BY clause using fixed allowlist.
   *
   * @param string $orderby Requested orderby field.
   * @param string $order   Requested order direction.
   * @return string
   */
  private function build_safe_orderby( $orderby, $order ) {
    $allowed_orderby = array(
      'created_at',
      'id',
      'user_id',
      'user_login',
      'action',
      'object_type',
      'object_name',
    );

    $orderby = sanitize_key( $orderby );
    if ( ! in_array( $orderby, $allowed_orderby, true ) ) {
      $orderby = 'created_at';
    }

    $order = strtoupper( sanitize_text_field( $order ) );
    $order = in_array( $order, array( 'ASC', 'DESC' ), true ) ? $order : 'DESC';

    return $orderby . ' ' . $order;
  }

  /**
   * Return validated custom table name.
   *
   * @return string
   */
  private function get_safe_table_name() {
    if ( preg_match( '/^[A-Za-z0-9_]+$/', $this->table_name ) ) {
      return $this->table_name;
    }

    global $wpdb;
    return $wpdb->prefix . 'pdt_admin_logs';
  }

  /**
   * Handle CSV export request (called early via admin_init)
   */
  public function handle_csv_export() {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    if ( ! isset( $_GET['page'] ) ) {
      return;
    }
    $page = sanitize_text_field( wp_unslash( $_GET['page'] ) );
    if ( $page !== 'polanger-activity-log' ) {
      return;
    }
    
    if ( ! isset( $_GET['pdt_export_logs'] ) ) {
      return;
    }
    
    if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'pdt_export_logs' ) ) {
      return;
    }
    
    if ( ! $this->can_current_user_view_logs() ) {
      return;
    }
    
    $this->export_csv();
  }

  /**
   * Handle clear logs request (called early via admin_init)
   */
  public function handle_clear_logs() {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    if ( ! isset( $_GET['page'] ) ) {
      return;
    }
    $page = sanitize_text_field( wp_unslash( $_GET['page'] ) );
    if ( $page !== 'polanger-activity-log' ) {
      return;
    }
    
    if ( ! isset( $_GET['pdt_clear_logs'] ) ) {
      return;
    }
    
    if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'pdt_clear_logs' ) ) {
      return;
    }
    
    if ( ! $this->can_current_user_view_logs() ) {
      return;
    }
    
    $this->clear_all_logs();
    
    wp_safe_redirect( admin_url( 'admin.php?page=polanger-activity-log&cleared=1' ) );
    exit;
  }

  /**
   * Export logs to CSV
   */
  public function export_csv( $args = array() ) {
    $args['per_page'] = 99999;
    $args['page'] = 1;
    $result = $this->get_logs( $args );

    $filename = 'admin-activity-log-' . gmdate( 'Y-m-d-His' ) . '.csv';

    header( 'Content-Type: text/csv; charset=utf-8' );
    header( 'Content-Disposition: attachment; filename=' . $filename );

    $output = fopen( 'php://output', 'w' );

    // Header row
    fputcsv(
      $output,
      array(
        __( 'ID', 'polanger-admin-menu-manager' ),
        __( 'Date', 'polanger-admin-menu-manager' ),
        __( 'User', 'polanger-admin-menu-manager' ),
        __( 'Action', 'polanger-admin-menu-manager' ),
        __( 'Object Type', 'polanger-admin-menu-manager' ),
        __( 'Object Name', 'polanger-admin-menu-manager' ),
        __( 'IP Address', 'polanger-admin-menu-manager' ),
      )
    );

    foreach ( $result['logs'] as $log ) {
      fputcsv( $output, array(
        $log->id,
        $log->created_at,
        $log->user_login,
        $log->action,
        $log->object_type,
        $log->object_name,
        $log->ip_address,
      ) );
    }

    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing php://output stream after CSV response.
    fclose( $output );
    exit;
  }

  /**
   * Delete a log entry
   */
  public function delete_log( $log_id ) {
    global $wpdb;
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Deleting selected row from custom log table.
    return $wpdb->delete( $this->table_name, array( 'id' => $log_id ), array( '%d' ) );
  }

  /**
   * Clear all logs
   */
  public function clear_all_logs() {
    global $wpdb;
    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Table truncate operation on plugin-owned table.
    return $wpdb->query( "TRUNCATE TABLE {$this->table_name}" );
  }

  /**
   * Cleanup old logs based on retention setting
   */
  public function cleanup_old_logs() {
    global $wpdb;

    $settings = $this->get_settings();
    $days = absint( $settings['retention_days'] );

    if ( $days > 0 ) {
      // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Scheduled retention cleanup on plugin-owned table.
      $wpdb->query( $wpdb->prepare(
        "DELETE FROM {$this->table_name} WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
        $days
      ) );
    }
  }

  /**
   * Get action label for display
   */
  public function get_action_label( $action ) {
    $labels = array(
      'user_login'              => __( 'User Login', 'polanger-admin-menu-manager' ),
      'user_logout'             => __( 'User Logout', 'polanger-admin-menu-manager' ),
      'login_failed'            => __( 'Failed Login', 'polanger-admin-menu-manager' ),
      'plugin_activated'        => __( 'Plugin Activated', 'polanger-admin-menu-manager' ),
      'plugin_deactivated'      => __( 'Plugin Deactivated', 'polanger-admin-menu-manager' ),
      'plugin_deleted'          => __( 'Plugin Deleted', 'polanger-admin-menu-manager' ),
      'plugin_updated'          => __( 'Plugin Updated', 'polanger-admin-menu-manager' ),
      'theme_switched'          => __( 'Theme Changed', 'polanger-admin-menu-manager' ),
      'customizer_saved'        => __( 'Customizer Saved', 'polanger-admin-menu-manager' ),
      'post_created'            => __( 'Post Created', 'polanger-admin-menu-manager' ),
      'post_updated'            => __( 'Post Updated', 'polanger-admin-menu-manager' ),
      'post_deleted'            => __( 'Post Deleted', 'polanger-admin-menu-manager' ),
      'post_trashed'            => __( 'Post Trashed', 'polanger-admin-menu-manager' ),
      'user_created'            => __( 'User Created', 'polanger-admin-menu-manager' ),
      'user_deleted'            => __( 'User Deleted', 'polanger-admin-menu-manager' ),
      'user_role_changed'       => __( 'User Role Changed', 'polanger-admin-menu-manager' ),
      'pdt_settings_changed'    => __( 'Plugin Settings Changed', 'polanger-admin-menu-manager' ),
      'menu_items_updated'      => __( 'Menu Items Updated', 'polanger-admin-menu-manager' ),
      'password_changed'        => __( 'Password Changed', 'polanger-admin-menu-manager' ),
      'password_reset_requested'=> __( 'Password Reset Requested', 'polanger-admin-menu-manager' ),
      'siteurl_changed'         => __( 'Site URL Changed', 'polanger-admin-menu-manager' ),
      'home_url_changed'        => __( 'Home URL Changed', 'polanger-admin-menu-manager' ),
      'admin_email_changed'     => __( 'Admin Email Changed', 'polanger-admin-menu-manager' ),
      'permalink_changed'       => __( 'Permalink Changed', 'polanger-admin-menu-manager' ),
    );

    return isset( $labels[ $action ] ) ? $labels[ $action ] : ucwords( str_replace( '_', ' ', $action ) );
  }

  /**
   * Get action icon class
   */
  public function get_action_icon( $action ) {
    $icons = array(
      'user_login'              => 'dashicons-admin-users',
      'user_logout'             => 'dashicons-migrate',
      'login_failed'            => 'dashicons-warning',
      'plugin_activated'        => 'dashicons-admin-plugins',
      'plugin_deactivated'      => 'dashicons-admin-plugins',
      'plugin_deleted'          => 'dashicons-trash',
      'plugin_updated'          => 'dashicons-update',
      'theme_switched'          => 'dashicons-admin-appearance',
      'customizer_saved'        => 'dashicons-admin-customizer',
      'post_created'            => 'dashicons-plus-alt',
      'post_updated'            => 'dashicons-edit',
      'post_deleted'            => 'dashicons-trash',
      'post_trashed'            => 'dashicons-trash',
      'user_created'            => 'dashicons-admin-users',
      'user_deleted'            => 'dashicons-trash',
      'user_role_changed'       => 'dashicons-groups',
      'pdt_settings_changed'    => 'dashicons-admin-settings',
      'menu_items_updated'      => 'dashicons-menu',
      'password_changed'        => 'dashicons-lock',
      'password_reset_requested'=> 'dashicons-unlock',
      'siteurl_changed'         => 'dashicons-admin-site',
      'home_url_changed'        => 'dashicons-admin-home',
      'admin_email_changed'     => 'dashicons-email-alt',
      'permalink_changed'       => 'dashicons-admin-links',
    );

    return isset( $icons[ $action ] ) ? $icons[ $action ] : 'dashicons-info';
  }

  /**
   * Get action severity level
   */
  public function get_action_severity( $action ) {
    return isset( $this->event_severity[ $action ] ) ? $this->event_severity[ $action ] : 'info';
  }

  /**
   * Get action color class based on severity
   */
  public function get_action_color( $action ) {
    $severity = $this->get_action_severity( $action );
    
    $severity_colors = array(
      'critical' => 'danger',
      'warning'  => 'warning',
      'info'     => 'info',
    );
    
    if ( isset( $severity_colors[ $severity ] ) ) {
      return $severity_colors[ $severity ];
    }
    
    // Fallback to old color mapping for non-severity events
    $colors = array(
      'user_login'          => 'success',
      'user_logout'         => 'info',
      'plugin_activated'    => 'success',
      'post_created'        => 'success',
      'user_created'        => 'success',
      'customizer_saved'    => 'info',
      'pdt_settings_changed'=> 'info',
      'menu_items_updated'  => 'info',
    );

    return isset( $colors[ $action ] ) ? $colors[ $action ] : 'info';
  }

  /**
   * Render settings page
   */
  public function render_settings_page() {
    $settings = $this->get_settings();
    $is_readonly = false;
    $can_manage_logs = current_user_can( 'manage_options' );

    global $pdt_settings_page;
    if ( $pdt_settings_page && method_exists( $pdt_settings_page, 'is_user_readonly' ) ) {
      $is_readonly = $pdt_settings_page->is_user_readonly();
    }
    
    // Handle form submission
    if ( isset( $_POST['pdt_activity_log_save'] ) && check_admin_referer( 'pdt_activity_log_settings' ) && ! $is_readonly && $can_manage_logs ) {
      $retention_days = isset( $_POST['retention_days'] ) ? absint( wp_unslash( $_POST['retention_days'] ) ) : 30;
      if ( ! in_array( $retention_days, array( 7, 30, 60, 90 ), true ) ) {
        $retention_days = 30;
      }

      $new_settings = array(
        'enabled'          => isset( $_POST['enabled'] ),
        'log_ip'           => isset( $_POST['log_ip'] ),
        'retention_days'   => $retention_days,
        'log_logins'       => isset( $_POST['log_logins'] ),
        'log_security'     => isset( $_POST['log_security'] ),
        'log_plugins'      => isset( $_POST['log_plugins'] ),
        'log_themes'       => isset( $_POST['log_themes'] ),
        'log_posts'        => isset( $_POST['log_posts'] ),
        'log_users'        => isset( $_POST['log_users'] ),
        'log_system'       => isset( $_POST['log_system'] ),
        'log_settings'     => isset( $_POST['log_settings'] ),
        'log_menus'        => isset( $_POST['log_menus'] ),
        'email_alerts'     => isset( $_POST['email_alerts'] ),
        'alert_email'      => isset( $_POST['alert_email'] ) ? sanitize_email( wp_unslash( $_POST['alert_email'] ) ) : '',
        'critical_actions' => isset( $_POST['critical_actions'] ) && is_array( $_POST['critical_actions'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['critical_actions'] ) ) : array(),
      );
      
      $this->update_settings( $new_settings );
      $settings = $new_settings;
      
      echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Settings saved.', 'polanger-admin-menu-manager' ) . '</p></div>';
    }
    
    ?>
    <form method="post" class="pdt-activity-log-settings">
      <?php wp_nonce_field( 'pdt_activity_log_settings' ); ?>
      <?php if ( ! $can_manage_logs ) : ?>
        <div class="notice notice-error inline"><p><?php esc_html_e( 'You do not have permission to manage Activity Log settings.', 'polanger-admin-menu-manager' ); ?></p></div>
      <?php endif; ?>
      <?php if ( $is_readonly ) : ?>
        <div class="notice notice-warning inline"><p><?php esc_html_e( 'Read-only mode is active. You can view these settings but cannot save changes.', 'polanger-admin-menu-manager' ); ?></p></div>
      <?php endif; ?>
      
      <!-- Enable/Disable -->
      <div class="pdt-settings-section">
        <h3><?php esc_html_e( 'Activity Logging', 'polanger-admin-menu-manager' ); ?></h3>
        
        <div class="pdt-consent-notice">
          <strong><?php esc_html_e( 'Privacy Notice', 'polanger-admin-menu-manager' ); ?></strong>
          <p class="pdt-consent-notice-text"><?php esc_html_e( 'This feature logs administrative actions for security and auditing purposes. Only administrative actions and technical metadata are logged. Sensitive fields such as passwords, emails, form inputs, and content data are never logged. Enabling this feature may be subject to GDPR/KVKK regulations.', 'polanger-admin-menu-manager' ); ?></p>
        </div>
        
        <label class="pdt-toggle-switch">
          <input type="checkbox" name="enabled" value="1" <?php checked( $settings['enabled'] ); ?> />
          <span class="pdt-toggle-slider"></span>
          <span class="pdt-toggle-label"><?php esc_html_e( 'Enable Activity Logging', 'polanger-admin-menu-manager' ); ?></span>
        </label>
      </div>
      
      <!-- What to Log -->
      <div class="pdt-settings-section">
        <h3><?php esc_html_e( 'Events to Log', 'polanger-admin-menu-manager' ); ?></h3>
        
        <div class="pdt-checkbox-grid">
          <label>
            <input type="checkbox" name="log_logins" value="1" <?php checked( $settings['log_logins'] ); ?> />
            <?php esc_html_e( 'Login / Logout', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_security" value="1" <?php checked( $settings['log_security'] ); ?> />
            <?php esc_html_e( 'Security Events', 'polanger-admin-menu-manager' ); ?>
            <span class="pdt-badge pdt-badge-new"><?php esc_html_e( 'New', 'polanger-admin-menu-manager' ); ?></span>
          </label>
          <label>
            <input type="checkbox" name="log_plugins" value="1" <?php checked( $settings['log_plugins'] ); ?> />
            <?php esc_html_e( 'Plugin Changes', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_themes" value="1" <?php checked( $settings['log_themes'] ); ?> />
            <?php esc_html_e( 'Theme Changes', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_posts" value="1" <?php checked( $settings['log_posts'] ); ?> />
            <?php esc_html_e( 'Post / Page Changes', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_users" value="1" <?php checked( $settings['log_users'] ); ?> />
            <?php esc_html_e( 'User Changes', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_system" value="1" <?php checked( $settings['log_system'] ); ?> />
            <?php esc_html_e( 'System Settings', 'polanger-admin-menu-manager' ); ?>
            <span class="pdt-badge pdt-badge-new"><?php esc_html_e( 'New', 'polanger-admin-menu-manager' ); ?></span>
          </label>
          <label>
            <input type="checkbox" name="log_settings" value="1" <?php checked( $settings['log_settings'] ); ?> />
            <?php esc_html_e( 'Plugin Settings', 'polanger-admin-menu-manager' ); ?>
          </label>
          <label>
            <input type="checkbox" name="log_menus" value="1" <?php checked( $settings['log_menus'] ); ?> />
            <?php esc_html_e( 'Menu Changes', 'polanger-admin-menu-manager' ); ?>
          </label>
        </div>
      </div>
      
      <!-- Privacy Settings -->
      <div class="pdt-settings-section">
        <h3><?php esc_html_e( 'Privacy & Retention', 'polanger-admin-menu-manager' ); ?></h3>
        
        <div class="pdt-form-row">
          <label>
            <input type="checkbox" name="log_ip" value="1" <?php checked( $settings['log_ip'] ); ?> />
            <?php esc_html_e( 'Log IP Addresses', 'polanger-admin-menu-manager' ); ?>
            <span class="pdt-help-text pdt-help-text-warning"><?php esc_html_e( '(May be subject to GDPR/KVKK)', 'polanger-admin-menu-manager' ); ?></span>
          </label>
        </div>
        
        <div class="pdt-form-row">
          <label for="retention_days"><?php esc_html_e( 'Auto-delete logs after:', 'polanger-admin-menu-manager' ); ?></label>
          <select name="retention_days" id="retention_days">
            <option value="7" <?php selected( $settings['retention_days'], 7 ); ?>><?php esc_html_e( '7 days', 'polanger-admin-menu-manager' ); ?></option>
            <option value="30" <?php selected( $settings['retention_days'], 30 ); ?>><?php esc_html_e( '30 days', 'polanger-admin-menu-manager' ); ?></option>
            <option value="60" <?php selected( $settings['retention_days'], 60 ); ?>><?php esc_html_e( '60 days', 'polanger-admin-menu-manager' ); ?></option>
            <option value="90" <?php selected( $settings['retention_days'], 90 ); ?>><?php esc_html_e( '90 days', 'polanger-admin-menu-manager' ); ?></option>
          </select>
        </div>
      </div>
      
      <!-- Email Alerts -->
      <div class="pdt-settings-section">
        <h3><?php esc_html_e( 'Email Alerts', 'polanger-admin-menu-manager' ); ?></h3>
        
        <div class="pdt-form-row">
          <label>
            <input type="checkbox" name="email_alerts" value="1" <?php checked( $settings['email_alerts'] ); ?> />
            <?php esc_html_e( 'Send email alerts for critical actions', 'polanger-admin-menu-manager' ); ?>
          </label>
        </div>
        
        <div class="pdt-form-row">
          <label for="alert_email"><?php esc_html_e( 'Alert Email:', 'polanger-admin-menu-manager' ); ?></label>
          <input type="email" name="alert_email" id="alert_email" value="<?php echo esc_attr( $settings['alert_email'] ); ?>" placeholder="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>" class="regular-text" />
        </div>
      </div>
      
      <p class="submit">
        <button type="submit" name="pdt_activity_log_save" class="button button-primary" <?php disabled( $is_readonly || ! $can_manage_logs ); ?>>
          <?php esc_html_e( 'Save Settings', 'polanger-admin-menu-manager' ); ?>
        </button>
      </p>
    </form>
    <?php
  }

  /**
   * Render logs viewer page
   */
  public function render_logs_page() {
    if ( ! $this->can_current_user_view_logs() ) {
      echo '<div class="notice notice-error"><p>' . esc_html__( 'You do not have permission to view activity logs.', 'polanger-admin-menu-manager' ) . '</p></div>';
      return;
    }

    // Export and Clear are now handled via admin_init hooks
    
    // Show success message after clear
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    if ( isset( $_GET['cleared'] ) && '1' === sanitize_text_field( wp_unslash( $_GET['cleared'] ) ) ) {
      echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'All logs have been cleared.', 'polanger-admin-menu-manager' ) . '</p></div>';
    }

    // Get filters.
    // phpcs:disable WordPress.Security.NonceVerification.Recommended
    $current_page = isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 1;
    $args = array(
      'page'        => $current_page,
      'per_page'    => 20,
      'user_id'     => isset( $_GET['user_id'] ) ? absint( wp_unslash( $_GET['user_id'] ) ) : null,
      'action'      => isset( $_GET['action_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['action_filter'] ) ) : null,
      'object_type' => isset( $_GET['object_type'] ) ? sanitize_text_field( wp_unslash( $_GET['object_type'] ) ) : null,
      'date_from'   => isset( $_GET['date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['date_from'] ) ) : null,
      'date_to'     => isset( $_GET['date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['date_to'] ) ) : null,
      'search'      => isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null,
    );
    // phpcs:enable WordPress.Security.NonceVerification.Recommended

    $result = $this->get_logs( $args );
    $actions = $this->get_unique_actions();
    $object_types = $this->get_unique_object_types();

    ?>
    <div class="pdt-activity-logs">
      
      <!-- Filters -->
      <div class="pdt-logs-filters">
        <form method="get" class="pdt-filter-form">
          <input type="hidden" name="page" value="polanger-activity-log" />
          
          <div class="pdt-filter-row">
            <input type="text" name="s" placeholder="<?php esc_attr_e( 'Search...', 'polanger-admin-menu-manager' ); ?>" value="<?php echo esc_attr( $args['search'] ); ?>" />
            
            <select name="action_filter">
              <option value=""><?php esc_html_e( 'All Actions', 'polanger-admin-menu-manager' ); ?></option>
              <?php foreach ( $actions as $action ) : ?>
                <option value="<?php echo esc_attr( $action ); ?>" <?php selected( $args['action'], $action ); ?>>
                  <?php echo esc_html( $this->get_action_label( $action ) ); ?>
                </option>
              <?php endforeach; ?>
            </select>
            
            <select name="object_type">
              <option value=""><?php esc_html_e( 'All Types', 'polanger-admin-menu-manager' ); ?></option>
              <?php foreach ( $object_types as $type ) : ?>
                <option value="<?php echo esc_attr( $type ); ?>" <?php selected( $args['object_type'], $type ); ?>>
                  <?php echo esc_html( ucfirst( $type ) ); ?>
                </option>
              <?php endforeach; ?>
            </select>
            
            <input type="date" name="date_from" value="<?php echo esc_attr( $args['date_from'] ); ?>" placeholder="<?php esc_attr_e( 'From', 'polanger-admin-menu-manager' ); ?>" />
            <input type="date" name="date_to" value="<?php echo esc_attr( $args['date_to'] ); ?>" placeholder="<?php esc_attr_e( 'To', 'polanger-admin-menu-manager' ); ?>" />
            
            <button type="submit" class="button"><?php esc_html_e( 'Filter', 'polanger-admin-menu-manager' ); ?></button>
            <a href="<?php echo esc_url( admin_url( 'admin.php?page=polanger-activity-log' ) ); ?>" class="button"><?php esc_html_e( 'Reset', 'polanger-admin-menu-manager' ); ?></a>
          </div>
        </form>
        
        <div class="pdt-logs-actions">
          <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'pdt_export_logs', '1' ), 'pdt_export_logs' ) ); ?>" class="pdt-btn-export"><span class="dashicons dashicons-download"></span><?php esc_html_e( 'Export CSV', 'polanger-admin-menu-manager' ); ?></a>
          <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=polanger-activity-log&pdt_clear_logs=1' ), 'pdt_clear_logs' ) ); ?>" class="pdt-btn-clear" data-confirm="<?php echo esc_attr__( 'Are you sure you want to delete all logs?', 'polanger-admin-menu-manager' ); ?>"><span class="dashicons dashicons-trash"></span><?php esc_html_e( 'Clear All', 'polanger-admin-menu-manager' ); ?></a>
        </div>
      </div>
      
      <!-- Stats -->
      <div class="pdt-logs-stats">
        <span>
          <?php
          /* translators: %d: Total number of logs. */
          printf( esc_html__( 'Total: %d logs', 'polanger-admin-menu-manager' ), absint( $result['total'] ) );
          ?>
        </span>
        <span>
          <?php
          /* translators: 1: Current page number, 2: Total page count. */
          printf( esc_html__( 'Page %1$d of %2$d', 'polanger-admin-menu-manager' ), absint( $result['page'] ), absint( max( 1, $result['pages'] ) ) );
          ?>
        </span>
      </div>
      
      <!-- Logs Table -->
      <table class="pdt-logs-table widefat striped">
        <thead>
          <tr>
            <th><?php esc_html_e( 'Date', 'polanger-admin-menu-manager' ); ?></th>
            <th><?php esc_html_e( 'User', 'polanger-admin-menu-manager' ); ?></th>
            <th><?php esc_html_e( 'Action', 'polanger-admin-menu-manager' ); ?></th>
            <th><?php esc_html_e( 'Object', 'polanger-admin-menu-manager' ); ?></th>
            <th><?php esc_html_e( 'IP', 'polanger-admin-menu-manager' ); ?></th>
          </tr>
        </thead>
        <tbody>
          <?php if ( empty( $result['logs'] ) ) : ?>
            <tr>
              <td colspan="5" class="pdt-logs-empty-cell">
                <?php esc_html_e( 'No logs found.', 'polanger-admin-menu-manager' ); ?>
              </td>
            </tr>
          <?php else : ?>
            <?php foreach ( $result['logs'] as $log ) : ?>
              <tr>
                <td>
                  <span class="pdt-log-date"><?php echo esc_html( gmdate( 'M j, Y', strtotime( $log->created_at ) ) ); ?></span>
                  <span class="pdt-log-time"><?php echo esc_html( gmdate( 'H:i:s', strtotime( $log->created_at ) ) ); ?></span>
                </td>
                <td>
                  <span class="pdt-log-user"><?php echo esc_html( $log->user_login ); ?></span>
                </td>
                <td>
                  <span class="pdt-severity-indicator pdt-severity-<?php echo esc_attr( $this->get_action_severity( $log->action ) ); ?>"></span>
                  <span class="pdt-log-action pdt-action-<?php echo esc_attr( $this->get_action_color( $log->action ) ); ?>">
                    <span class="dashicons <?php echo esc_attr( $this->get_action_icon( $log->action ) ); ?>"></span>
                    <?php echo esc_html( $this->get_action_label( $log->action ) ); ?>
                  </span>
                </td>
                <td>
                  <?php if ( $log->object_name ) : ?>
                    <span class="pdt-log-object">
                      <?php if ( $log->object_type ) : ?>
                        <span class="pdt-object-type"><?php echo esc_html( ucfirst( $log->object_type ) ); ?>:</span>
                      <?php endif; ?>
                      <?php echo esc_html( $log->object_name ); ?>
                    </span>
                  <?php else : ?>
                    <span class="pdt-log-na">—</span>
                  <?php endif; ?>
                </td>
                <td>
                  <?php if ( $log->ip_address ) : ?>
                    <code class="pdt-log-ip"><?php echo esc_html( $log->ip_address ); ?></code>
                  <?php else : ?>
                    <span class="pdt-log-na">—</span>
                  <?php endif; ?>
                </td>
              </tr>
            <?php endforeach; ?>
          <?php endif; ?>
        </tbody>
      </table>
      
      <!-- Pagination -->
      <?php if ( $result['pages'] > 1 ) : ?>
        <div class="pdt-logs-pagination">
          <?php
          $base_url = admin_url( 'admin.php?page=polanger-activity-log' );
          foreach ( $args as $key => $value ) {
            if ( $value && $key !== 'page' && $key !== 'per_page' ) {
              $param_key = $key === 'action' ? 'action_filter' : $key;
              $base_url = add_query_arg( $param_key, $value, $base_url );
            }
          }
          
          echo wp_kses_post(
            paginate_links(
              array(
                'base'      => add_query_arg( 'paged', '%#%', $base_url ),
                'format'    => '',
                'current'   => absint( $result['page'] ),
                'total'     => absint( $result['pages'] ),
                'prev_text' => '&laquo;',
                'next_text' => '&raquo;',
              )
            )
          );
          ?>
        </div>
      <?php endif; ?>
      
    </div>
    <?php
  }

}
