<?php
/**
 * CLAWS API Class
 * Handles all REST API endpoints for the CLAWS app
 */

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

class CLAWS_API {
    
    private static $instance = null;
    private $database;
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        $this->database = CLAWS_Database::getInstance();
        add_action('rest_api_init', array($this, 'register_routes'));
    }
    
    public function register_routes() {
        try {
            $namespace = 'claws/v1';
        
        // User authentication
        register_rest_route($namespace, '/user', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_current_user'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // COLONIES
        register_rest_route($namespace, '/colonies', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_colonies'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/colony', array(
            'methods' => 'POST',
            'callback' => array($this, 'save_colony'),
            'permission_callback' => array($this, 'user_logged_in'),
            'args' => $this->get_colony_schema()
        ));
        
        register_rest_route($namespace, '/colony/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_colony'),
            'permission_callback' => array($this, 'user_can_edit_colony')
        ));
        
        register_rest_route($namespace, '/colony/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_colony'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        
        
        // CLEANUP
        register_rest_route($namespace, '/colonies/cleanup-duplicates', array(
            'methods' => 'POST',
            'callback' => array($this, 'cleanup_duplicate_colonies'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/colonies/export', array(
            'methods' => 'GET',
            'callback' => array($this, 'export_colony_data'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        
        // INTAKES
        register_rest_route($namespace, '/intake', array(
            'methods' => 'POST',
            'callback' => array($this, 'save_intake'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/intakes', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_user_intakes'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/intake/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_intake_record'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // DISCHARGES
        register_rest_route($namespace, '/discharge', array(
            'methods' => 'POST',
            'callback' => array($this, 'save_discharge'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/discharges', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_user_discharges'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // ADMIN AGGREGATE ANALYTICS
        register_rest_route($namespace, '/admin/intakes/aggregate', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_aggregate_intake_analytics'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/admin/discharges/aggregate', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_aggregate_discharge_analytics'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        // NEONATE CARE / FEEDING RECORDS
        register_rest_route($namespace, '/feeding', array(
            'methods' => 'POST',
            'callback' => array($this, 'save_feeding_record'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/feedings', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_user_feeding_records'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/feeding/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_feeding_record'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/feeding/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_feeding_record'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/baby-kittens', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_baby_kittens'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/colony/(?P<id>\d+)/history', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_colony_history'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // FEEDING RECORD BULK DELETION (Admin only)
        register_rest_route($namespace, '/feeding/bulk-delete', array(
            'methods' => 'POST',
            'callback' => array($this, 'bulk_delete_feeding_records'),
            'permission_callback' => array($this, 'user_is_admin'),
            'args' => array(
                'start_date' => array(
                    'required' => true,
                    'type' => 'string',
                    'sanitize_callback' => 'sanitize_text_field'
                ),
                'end_date' => array(
                    'required' => true,
                    'type' => 'string',
                    'sanitize_callback' => 'sanitize_text_field'
                ),
                'exclude_active_kittens' => array(
                    'required' => false,
                    'type' => 'boolean',
                    'default' => true
                )
            )
        ));
        
        // GEOCODING
        register_rest_route($namespace, '/geocode', array(
            'methods' => 'POST',
            'callback' => array($this, 'geocode_address'),
            'permission_callback' => array($this, 'user_logged_in'),
            'args' => array(
                'address' => array(
                    'required' => true,
                    'type' => 'string',
                    'sanitize_callback' => 'sanitize_text_field'
                )
            )
        ));
        
        // PHOTO UPLOADS
        register_rest_route($namespace, '/colony/(?P<id>\d+)/photo', array(
            'methods' => 'POST',
            'callback' => array($this, 'upload_colony_photo'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/intake/(?P<id>\d+)/photo', array(
            'methods' => 'POST',
            'callback' => array($this, 'upload_intake_photo'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/discharge/(?P<id>\d+)/photo', array(
            'methods' => 'POST',
            'callback' => array($this, 'upload_discharge_photo'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // ADMIN REPORTS
        register_rest_route($namespace, '/admin/report', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_admin_report'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        // ADMIN AGGREGATE DATA FOR CHARTS
        register_rest_route($namespace, '/admin/intakes', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_all_intakes'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/admin/discharges', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_all_discharges'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        // ANALYTICS TRACKING
        register_rest_route($namespace, '/analytics/track', array(
            'methods' => 'POST',
            'callback' => array($this, 'track_feature_usage'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // COORDINATORS LIST (Editors/Admins for task approval)
        register_rest_route($namespace, '/coordinators', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_coordinators'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // ALL VOLUNTEERS LIST (For event spot reservations)
        register_rest_route($namespace, '/volunteers', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_all_volunteers'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // VOLUNTEER TIME ENTRY
        register_rest_route($namespace, '/volunteer-time', array(
            'methods' => 'POST',
            'callback' => array($this, 'save_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/pending', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_pending_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/approved', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_approved_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/(?P<id>\d+)/approve', array(
            'methods' => 'POST',
            'callback' => array($this, 'approve_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/(?P<id>\d+)/reject', array(
            'methods' => 'POST',
            'callback' => array($this, 'reject_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/(?P<id>\d+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/volunteer-time/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_volunteer_time'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // EVENTS
        register_rest_route($namespace, '/events', array(
            'methods' => 'POST',
            'callback' => array($this, 'create_event'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_all_events'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/available', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_available_events'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/available', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_available_projects'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_all_projects'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)/decline', array(
            'methods' => 'POST',
            'callback' => array($this, 'decline_event_reservation'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)/confirm', array(
            'methods' => 'POST',
            'callback' => array($this, 'confirm_event_reservation'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)/claim-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'claim_event_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)/unclaim-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'unclaim_event_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)/decline-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'decline_event_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_event'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_event'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/events/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_event'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/(?P<id>\d+)/claim-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'claim_project_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/(?P<id>\d+)/unclaim-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'unclaim_project_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/(?P<id>\d+)/decline-spot', array(
            'methods' => 'POST',
            'callback' => array($this, 'decline_project_spot'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/(?P<id>\d+)/retire', array(
            'methods' => 'POST',
            'callback' => array($this, 'retire_project'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // Individual project CRUD
        register_rest_route($namespace, '/projects/(?P<id>\d+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_project'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/projects/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_project'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // TEAMS (auto-generated from events/projects)
        register_rest_route($namespace, '/teams/events', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_event_teams'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/teams/projects', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_project_teams'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // STATS
        register_rest_route($namespace, '/stats/personal', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_personal_stats'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/stats/organization', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_organization_stats'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/stats/top-volunteers', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_top_volunteers'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/stats/mover-shaker', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_mover_shaker'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/stats/volunteer-hours', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_volunteer_hours'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        register_rest_route($namespace, '/stats/team-hours', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_team_hours'),
            'permission_callback' => array($this, 'user_is_admin')
        ));
        
        // MESSAGES
        register_rest_route($namespace, '/messages/send', array(
            'methods' => 'POST',
            'callback' => array($this, 'send_chat_message'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/messages/(?P<type>team|individual)/(?P<id>\d+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_chat_messages'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // NOTIFICATIONS CHECK
        register_rest_route($namespace, '/notifications/check', array(
            'methods' => 'GET',
            'callback' => array($this, 'check_notifications'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/messages/unread-counts', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_unread_message_counts'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        register_rest_route($namespace, '/messages/clear/(?P<type>team|individual)/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'clear_conversation'),
            'permission_callback' => array($this, 'user_logged_in')
        ));
        
        // DONOR ENDPOINTS
        register_rest_route($namespace, '/donors', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_donors'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/donors', array(
            'methods' => 'POST',
            'callback' => array($this, 'create_donor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/donors/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_donor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/donors/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_donor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        // SPONSOR ENDPOINTS
        register_rest_route($namespace, '/sponsors', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_sponsors'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/sponsors', array(
            'methods' => 'POST',
            'callback' => array($this, 'create_sponsor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/sponsors/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_sponsor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/sponsors/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_sponsor'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        // VOLUNTEER APPLICATION ENDPOINTS
        register_rest_route($namespace, '/volunteer-applications', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_volunteer_applications'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/volunteer-applications', array(
            'methods' => 'POST',
            'callback' => array($this, 'create_volunteer_application'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/volunteer-applications/(?P<id>\d+)/approve', array(
            'methods' => 'POST',
            'callback' => array($this, 'approve_volunteer_application'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        register_rest_route($namespace, '/volunteer-applications/(?P<id>\d+)/deny', array(
            'methods' => 'POST',
            'callback' => array($this, 'deny_volunteer_application'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        // CONTACT ENDPOINTS
        register_rest_route($namespace, '/contacts', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_contacts'),
            'permission_callback' => '__return_true'  // TEMP: Open to diagnose issue
        ));
        
        register_rest_route($namespace, '/contacts', array(
            'methods' => 'POST',
            'callback' => array($this, 'create_contact'),
            'permission_callback' => '__return_true'  // TEMP: Open to diagnose issue
        ));
        
        register_rest_route($namespace, '/contacts/(?P<id>\d+)', array(
            'methods' => 'PUT',
            'callback' => array($this, 'update_contact'),
            'permission_callback' => '__return_true'  // TEMP: Open to diagnose issue
        ));
        
        register_rest_route($namespace, '/contacts/(?P<id>\d+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'delete_contact'),
            'permission_callback' => '__return_true'  // TEMP: Open to diagnose issue
        ));
        
        register_rest_route($namespace, '/contacts/(?P<id>\d+)/elevate', array(
            'methods' => 'POST',
            'callback' => array($this, 'elevate_contact_to_volunteer'),
            'permission_callback' => '__return_true'  // TEMP: Open to diagnose issue
        ));
        
        // USERNAME MATCHING
        register_rest_route($namespace, '/match-username', array(
            'methods' => 'POST',
            'callback' => array($this, 'match_username_by_email'),
            'permission_callback' => array($this, 'is_admin')
        ));
        
        } catch (Exception $e) {
            error_log('CLAWS REST API Registration Error: ' . $e->getMessage());
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('CLAWS REST API Error Trace: ' . $e->getTraceAsString());
            }
        }
    }
    
    /**
     * Permission callbacks
     */
    public function user_logged_in() {
        return is_user_logged_in();
    }
    
    public function is_admin() {
        return current_user_can('manage_options');
    }
    
    /**
     * Check if user can access admin features (Editors and Administrators)
     * Editors are "Admin Lite" with full app access but no backend WP menu
     */
    public function can_access_admin_features() {
        if (!is_user_logged_in()) {
            return false;
        }
        
        $user = wp_get_current_user();
        $user_roles = $user->roles;
        
        // Allow administrators and editors
        return in_array('administrator', $user_roles) || in_array('editor', $user_roles);
    }
    
    public function user_is_admin() {
        return current_user_can('manage_options');
    }
    
    public function user_can_edit_colony($request) {
        if (!is_user_logged_in()) {
            return false;
        }
        
        $colony_id = intval($request['id']);
        $post = get_post($colony_id);
        
        if (!$post || $post->post_type !== 'claws_colony') {
            return false;
        }
        
        $current_user_id = get_current_user_id();
        $user = get_userdata($current_user_id);
        $user_roles = $user ? $user->roles : array();
        
        // Admins can edit any colony
        if (in_array('administrator', $user_roles)) {
            return true;
        }
        
        // Authors can edit any colony  
        if (in_array('author', $user_roles)) {
            return true;
        }
        
        // Contributors can only edit their own colonies
        if (in_array('contributor', $user_roles)) {
            return ($post->post_author == $current_user_id);
        }
        
        return false;
    }
    
    public function user_can_view_colony($colony_id) {
        if (!is_user_logged_in()) {
            return false;
        }
        
        $post = get_post($colony_id);
        if (!$post || $post->post_type !== 'claws_colony') {
            return false;
        }
        
        $current_user_id = get_current_user_id();
        $user = get_userdata($current_user_id);
        $user_roles = $user ? $user->roles : array();
        
        // Admins can view any colony
        if (in_array('administrator', $user_roles)) {
            return true;
        }
        
        // Authors can view any colony  
        if (in_array('author', $user_roles)) {
            return true;
        }
        
        // Contributors can only view their own colonies
        if (in_array('contributor', $user_roles)) {
            return ($post->post_author == $current_user_id);
        }
        
        return false;
    }
    
    /**
     * Get colony validation schema
     */
    private function get_colony_schema() {
        return array(
            'name' => array(
                'required' => true,
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field'
            ),
            'address' => array(
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field'
            ),
            'lat' => array(
                'type' => 'number',
                'validate_callback' => array($this, 'validate_latitude')
            ),
            'lng' => array(
                'type' => 'number',
                'validate_callback' => array($this, 'validate_longitude')
            ),
            'caregivers' => array(
                'type' => 'array',
                'sanitize_callback' => array($this, 'sanitize_caregivers'),
                'validate_callback' => array($this, 'validate_caregivers')
            )
        );
    }
    
    /**
     * Validation functions
     */
    public function validate_latitude($value) {
        return is_numeric($value) && $value >= -90 && $value <= 90;
    }
    
    public function validate_longitude($value) {
        return is_numeric($value) && $value >= -180 && $value <= 180;
    }
    
    public function validate_caregivers($value) {
        if (!is_array($value)) {
            return false;
        }
        
        foreach ($value as $caregiver) {
            if (!is_array($caregiver)) {
                return false;
            }
            
            // Caregiver must have at least a name
            if (!isset($caregiver['name']) || empty(trim($caregiver['name']))) {
                return false;
            }
            
            // Validate email if provided
            if (isset($caregiver['email']) && !empty($caregiver['email']) && !is_email($caregiver['email'])) {
                return false;
            }
        }
        
        return true;
    }
    
    public function sanitize_caregivers($value) {
        if (!is_array($value)) {
            return array();
        }
        
        $sanitized = array();
        foreach ($value as $caregiver) {
            if (!is_array($caregiver)) {
                continue;
            }
            
            $sanitized_caregiver = array();
            
            if (isset($caregiver['name'])) {
                $sanitized_caregiver['name'] = sanitize_text_field($caregiver['name']);
            }
            
            if (isset($caregiver['email'])) {
                $sanitized_caregiver['email'] = sanitize_email($caregiver['email']);
            }
            
            if (isset($caregiver['phone'])) {
                $sanitized_caregiver['phone'] = sanitize_text_field($caregiver['phone']);
            }
            
            if (isset($caregiver['isPublic'])) {
                $sanitized_caregiver['isPublic'] = (bool) $caregiver['isPublic'];
            }
            
            // Only add caregiver if they have a name
            if (!empty($sanitized_caregiver['name'])) {
                $sanitized[] = $sanitized_caregiver;
            }
        }
        
        return $sanitized;
    }
    
    /**
     * API Endpoints
     */
    public function get_current_user($request) {
        $user = wp_get_current_user();
        return new WP_REST_Response(array(
            'id' => $user->ID,
            'name' => $user->display_name,
            'email' => $user->user_email,
            'role' => isset($user->roles[0]) ? $user->roles[0] : 'subscriber',
            'is_admin' => current_user_can('manage_options'),
            'can_edit_colonies' => current_user_can('edit_posts')
        ), 200);
    }
    
    public function get_colonies($request) {
        try {
            $current_user_id = get_current_user_id();
            
            // Let WordPress and User Role Editor plugin handle permissions
            $colonies = $this->database->get_colonies($current_user_id);
            
            return new WP_REST_Response($colonies, 200);
        } catch (Exception $e) {
            claws_log('Error getting colonies: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve colonies', array('status' => 500));
        }
    }
    
    public function save_colony($request) {
        try {
            claws_log('Save colony API endpoint called');
            
            $user_id = get_current_user_id();
            claws_log('User ID: ' . $user_id);
            
            if (!$user_id) {
                claws_log('User not logged in', 'error');
                return new WP_Error('not_logged_in', 'You must be logged in to save colonies', array('status' => 401));
            }
            
            // Let WordPress handle permissions via post type capabilities
            
            $colony_data = $request->get_json_params();
            claws_log('Colony data received: ' . print_r($colony_data, true));
            
            if (empty($colony_data)) {
                claws_log('No colony data received', 'error');
                return new WP_Error('no_data', 'No colony data received', array('status' => 400));
            }
            
            $result = $this->database->save_colony($colony_data, $user_id);
            claws_log('Database save result: ' . print_r($result, true));
            
            if (is_wp_error($result)) {
                claws_log('Database error: ' . $result->get_error_message(), 'error');
                return $result;
            }
            
            claws_log('Colony saved successfully with ID: ' . $result);
            
            // Trigger Zapier webhook
            do_action('claws_colony_saved', $result, $colony_data);
            
            return new WP_REST_Response(array(
                'success' => true,
                'id' => $result,
                'message' => 'Colony saved successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error saving colony: ' . $e->getMessage(), 'error');
            return new WP_Error('save_failed', 'An error occurred while saving the colony', array('status' => 500));
        }
    }
    
    public function update_colony($request) {
        try {
            $colony_id = absint($request['id']);
            $user_id = get_current_user_id();
            $colony_data = $request->get_json_params();
            
            // Verify colony exists
            $post = get_post($colony_id);
            if (!$post || $post->post_type !== 'claws_colony') {
                return new WP_Error('invalid_colony', 'Colony not found', array('status' => 404));
            }
            
            // Update colony title
            $updated = wp_update_post(array(
                'ID' => $colony_id,
                'post_title' => sanitize_text_field($colony_data['name'])
            ), true);
            
            if (is_wp_error($updated)) {
                return new WP_Error('update_failed', 'Could not update colony', array('status' => 500));
            }
            
            // Get original metadata values before update (needed for historical edit revert)
            $meta_field_keys = array('cats_total', 'cats_babies', 'cats_kittens', 'cats_adults', 'cats_seniors', 'tipped_ears', 'winter_shelters', 'food_security', 'water_security', 'safe_location', 'capture_method', 'vaccinated_count', 'microchip_count', 'tnr_no_tipping', 'volunteer_help', 'caregiver', 'caregiver_id', 'caregivers', 'assigned_user_id', 'address', 'street', 'city', 'state', 'zip');
            $original_meta_values = array();
            foreach ($meta_field_keys as $key) {
                $original_meta_values[$key] = get_post_meta($colony_id, $key, true);
            }
            
            $meta_fields = array(
                'cats_total' => isset($colony_data['cats']) ? absint($colony_data['cats']) : 0,
                'cats_babies' => isset($colony_data['babies']) ? absint($colony_data['babies']) : 0,
                'cats_kittens' => isset($colony_data['kittens']) ? absint($colony_data['kittens']) : 0,
                'cats_adults' => isset($colony_data['adults']) ? absint($colony_data['adults']) : 0,
                'cats_seniors' => isset($colony_data['seniors']) ? absint($colony_data['seniors']) : 0,
                'tipped_ears' => isset($colony_data['tippedEars']) ? absint($colony_data['tippedEars']) : 0,
                'winter_shelters' => isset($colony_data['winterShelters']) ? absint($colony_data['winterShelters']) : 0,
                'food_security' => isset($colony_data['foodSecurity']) ? sanitize_text_field($colony_data['foodSecurity']) : '',
                'water_security' => isset($colony_data['waterSecurity']) ? sanitize_text_field($colony_data['waterSecurity']) : '',
                'safe_location' => isset($colony_data['safeLocation']) ? sanitize_text_field($colony_data['safeLocation']) : '',
                'capture_method' => isset($colony_data['captureMethod']) ? sanitize_text_field($colony_data['captureMethod']) : '',
                'vaccinated_count' => isset($colony_data['vaccinatedCount']) ? $colony_data['vaccinatedCount'] : 'unknown',
                'microchip_count' => isset($colony_data['microchipCount']) ? $colony_data['microchipCount'] : 'unknown',
                'tnr_no_tipping' => isset($colony_data['tnrNoTipping']) ? (bool)$colony_data['tnrNoTipping'] : false,
                'volunteer_help' => isset($colony_data['volunteerHelp']) ? wp_json_encode($colony_data['volunteerHelp']) : '',
                'caregiver' => isset($colony_data['caregiver']) ? sanitize_text_field($colony_data['caregiver']) : '',
                'caregiver_id' => isset($colony_data['caregiverId']) ? intval($colony_data['caregiverId']) : null,
                'caregivers' => isset($colony_data['caregivers']) ? wp_json_encode($colony_data['caregivers']) : '',
                'assigned_user_id' => isset($colony_data['assignedUserId']) ? intval($colony_data['assignedUserId']) : null,
                
                // Address fields - MISSING FROM ORIGINAL CODE
                'address' => isset($colony_data['address']) ? sanitize_text_field($colony_data['address']) : '',
                'street' => isset($colony_data['street']) ? sanitize_text_field($colony_data['street']) : '',
                'city' => isset($colony_data['city']) ? sanitize_text_field($colony_data['city']) : '',
                'state' => isset($colony_data['state']) ? sanitize_text_field($colony_data['state']) : '',
                'zip' => isset($colony_data['zip']) ? sanitize_text_field($colony_data['zip']) : '',
                
                // Location coordinates - REMOVED: Should never be updated after colony creation (like name)
                
                'last_updated' => current_time('mysql'),
                'last_updated_by' => $user_id
            );
            
            foreach ($meta_fields as $key => $value) {
                update_post_meta($colony_id, $key, $value);
            }
            
            // Handle historical record logic
            $effective_date = isset($colony_data['effectiveDate']) ? $colony_data['effectiveDate'] : current_time('Y-m-d');
            $creation_date = $this->database->get_colony_creation_date($colony_id);
            
            if ($creation_date) {
                $creation_date_only = date('Y-m-d', strtotime($creation_date));
                
                // If effective date is after creation date, update colony AND create history
                if (strtotime($effective_date) >= strtotime($creation_date_only)) {
                    // Colony is already updated above, just create historical record
                    $history_result = $this->database->create_colony_history_post($colony_id, $colony_data, $user_id, $effective_date);
                    if (is_wp_error($history_result)) {
                        claws_log("Warning: Could not create historical record: " . $history_result->get_error_message(), 'warning');
                    }
                } else {
                    // If effective date is before creation date, only create historical record
                    // Revert the colony metadata changes since this is historical data only
                    claws_log("Reverting metadata changes for historical edit (effective date: $effective_date before creation date: $creation_date_only)");
                    
                    // Revert each metadata field to its original value
                    foreach ($meta_fields as $key => $new_value) {
                        $original_value = $original_meta_values[$key];
                        update_post_meta($colony_id, $key, $original_value);
                        claws_log("Reverted $key from $new_value back to $original_value");
                    }
                    
                    $history_result = $this->database->create_colony_history_post($colony_id, $colony_data, $user_id, $effective_date);
                    if (is_wp_error($history_result)) {
                        claws_log("Warning: Could not create historical record: " . $history_result->get_error_message(), 'warning');
                    }
                }
            }
            
            return new WP_REST_Response(array(
                'success' => true
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error updating colony: ' . $e->getMessage(), 'error');
            return new WP_Error('update_failed', 'An error occurred while updating the colony', array('status' => 500));
        }
    }
    
    
    public function cleanup_duplicate_colonies($request) {
        try {
            // Only allow admins to run cleanup
            if (!current_user_can('manage_options')) {
                return new WP_Error('insufficient_permissions', 'You must be an admin to run cleanup', array('status' => 403));
            }
            
            $result = $this->database->cleanup_duplicate_colonies();
            
            return new WP_REST_Response(array(
                'success' => true,
                'deleted_count' => $result['deleted_count'],
                'remaining_colonies' => $result['remaining_colonies'],
                'message' => "Cleanup complete: Deleted {$result['deleted_count']} duplicate colonies, {$result['remaining_colonies']} unique colonies remain"
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error running cleanup: ' . $e->getMessage(), 'error');
            return new WP_Error('cleanup_failed', 'An error occurred during cleanup', array('status' => 500));
        }
    }
    
    public function delete_colony($request) {
        try {
            $colony_id = absint($request['id']);
            
            $post = get_post($colony_id);
            if (!$post || $post->post_type !== 'claws_colony') {
                return new WP_Error('invalid_colony', 'Colony not found', array('status' => 404));
            }
            
            $deleted = wp_delete_post($colony_id, true);
            
            if ($deleted) {
                claws_log("Colony deleted: {$post->post_title} (ID: {$colony_id})");
                return new WP_REST_Response(array('success' => true), 200);
            } else {
                return new WP_Error('delete_failed', 'Could not delete colony', array('status' => 500));
            }
            
        } catch (Exception $e) {
            claws_log('Error deleting colony: ' . $e->getMessage(), 'error');
            return new WP_Error('delete_failed', 'An error occurred while deleting the colony', array('status' => 500));
        }
    }
    
    
    
    
    
    
    
    
    
    
    public function save_intake($request) {
        try {
            $user_id = get_current_user_id();
            $intake_data = $request->get_json_params();
            
            $result = $this->database->save_intake($intake_data, $user_id);
            
            if (is_wp_error($result)) {
                return $result;
            }
            
            // Trigger Zapier webhook
            do_action('claws_intake_saved', $result, $intake_data);
            
            return new WP_REST_Response(array(
                'success' => true,
                'id' => $result,
                'message' => 'Intake record saved successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error saving intake: ' . $e->getMessage(), 'error');
            return new WP_Error('save_failed', 'Could not save intake record', array('status' => 500));
        }
    }
    
    public function get_user_intakes($request) {
        try {
            $user_id = get_current_user_id();
            $intakes = $this->database->get_user_intakes($user_id);

            // Enrich with author display name for exports/UI convenience
            $author_info = get_userdata($user_id);
            $author_name = $author_info ? $author_info->display_name : 'Unknown';
            foreach ($intakes as &$intake) {
                // Keep both keys for backward compatibility across UI code paths
                $intake['author'] = $intake['author'] ?? $user_id;
                $intake['user_id'] = $intake['user_id'] ?? $user_id;
                $intake['author_name'] = $intake['author_name'] ?? $author_name;
                $intake['added_by_name'] = $intake['added_by_name'] ?? $author_name;
            }
            unset($intake);
            
            return new WP_REST_Response($intakes, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting intakes: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve intake records', array('status' => 500));
        }
    }
    
    public function save_discharge($request) {
        try {
            $user_id = get_current_user_id();
            $discharge_data = $request->get_json_params();
            
            claws_log("API: save_discharge called");
            claws_log("Discharge data received: " . json_encode($discharge_data));
            
            $result = $this->database->save_discharge($discharge_data, $user_id);
            
            if (is_wp_error($result)) {
                claws_log("ERROR: save_discharge failed: " . $result->get_error_message());
                return $result;
            }
            
            claws_log("✅ Discharge saved with ID: {$result}");
            
            // **NEW: Handle automatic colony count adjustment for discharged cats**
            if (isset($discharge_data['cat_name']) && isset($discharge_data['outcome'])) {
                claws_log("Checking if colony adjustment needed for: {$discharge_data['cat_name']} (outcome: {$discharge_data['outcome']})");
                
                $adjustment_result = $this->database->handle_discharge_colony_adjustment(
                    $discharge_data, 
                    $user_id
                );
                
                if ($adjustment_result) {
                    claws_log("✅ Colony adjustment completed: " . json_encode($adjustment_result));
                } else {
                    claws_log("ℹ️ No colony adjustment performed (cat may not be from a colony, or outcome doesn't require adjustment)");
                }
            } else {
                claws_log("⚠️ Missing cat_name or outcome in discharge data - cannot check colony adjustment");
            }
            
            // Trigger Zapier webhook
            do_action('claws_discharge_saved', $result, $discharge_data);
            
            return new WP_REST_Response(array(
                'success' => true,
                'id' => $result,
                'message' => 'Discharge record saved successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('❌ ERROR saving discharge: ' . $e->getMessage(), 'error');
            return new WP_Error('save_failed', 'Could not save discharge record', array('status' => 500));
        }
    }
    
    public function update_intake_record($request) {
        try {
            $user_id = get_current_user_id();
            $record_id = absint($request['id']);
            $intake_data = $request->get_json_params();
            
            $result = $this->database->update_intake_record($record_id, $intake_data, $user_id);
            
            if (is_wp_error($result)) {
                return $result;
            }
            
            return new WP_REST_Response(array(
                'success' => true,
                'message' => 'Intake record updated successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error updating intake record: ' . $e->getMessage(), 'error');
            return new WP_Error('update_failed', 'Could not update intake record', array('status' => 500));
        }
    }
    
    public function get_user_discharges($request) {
        try {
            $user_id = get_current_user_id();
            $discharges = $this->database->get_user_discharges($user_id);

            // Enrich with author display name for exports/UI convenience
            $author_info = get_userdata($user_id);
            $author_name = $author_info ? $author_info->display_name : 'Unknown';
            foreach ($discharges as &$discharge) {
                $discharge['author'] = $discharge['author'] ?? $user_id;
                $discharge['user_id'] = $discharge['user_id'] ?? $user_id;
                $discharge['author_name'] = $discharge['author_name'] ?? $author_name;
                $discharge['added_by_name'] = $discharge['added_by_name'] ?? $author_name;
            }
            unset($discharge);
            
            return new WP_REST_Response($discharges, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting discharges: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve discharge records', array('status' => 500));
        }
    }
    
    public function get_aggregate_intake_analytics($request) {
        try {
            $analytics = $this->database->get_aggregate_intake_analytics();
            
            return new WP_REST_Response($analytics, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting aggregate intake analytics: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve aggregate intake analytics', array('status' => 500));
        }
    }
    
    public function get_aggregate_discharge_analytics($request) {
        try {
            $analytics = $this->database->get_aggregate_discharge_analytics();
            
            return new WP_REST_Response($analytics, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting aggregate discharge analytics: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve aggregate discharge analytics', array('status' => 500));
        }
    }
    
    public function save_feeding_record($request) {
        try {
            $user_id = get_current_user_id();
            $feeding_data = $request->get_json_params();
            
            $result = $this->database->save_feeding_record($feeding_data, $user_id);
            
            if (is_wp_error($result)) {
                return $result;
            }
            
            return new WP_REST_Response(array(
                'success' => true,
                'id' => $result,
                'message' => 'Feeding record saved successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error saving feeding record: ' . $e->getMessage(), 'error');
            return new WP_Error('save_failed', 'Could not save feeding record', array('status' => 500));
        }
    }
    
    public function update_feeding_record($request) {
        try {
            $user_id = get_current_user_id();
            $record_id = absint($request['id']);
            $feeding_data = $request->get_json_params();
            
            $result = $this->database->update_feeding_record($record_id, $feeding_data, $user_id);
            
            if (is_wp_error($result)) {
                return $result;
            }
            
            return new WP_REST_Response(array(
                'success' => true,
                'message' => 'Feeding record updated successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error updating feeding record: ' . $e->getMessage(), 'error');
            return new WP_Error('update_failed', 'Could not update feeding record', array('status' => 500));
        }
    }
    
    public function get_user_feeding_records($request) {
        try {
            $user_id = get_current_user_id();
            $records = $this->database->get_user_feeding_records($user_id);
            
            return new WP_REST_Response($records, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting feeding records: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve feeding records', array('status' => 500));
        }
    }
    
    public function delete_feeding_record($request) {
        try {
            $user_id = get_current_user_id();
            $record_id = absint($request['id']);
            
            $result = $this->database->delete_feeding_record($record_id, $user_id);
            
            if ($result) {
                return new WP_REST_Response(array('success' => true), 200);
            } else {
                return new WP_Error('delete_failed', 'Could not delete feeding record', array('status' => 500));
            }
            
        } catch (Exception $e) {
            claws_log('Error deleting feeding record: ' . $e->getMessage(), 'error');
            return new WP_Error('delete_failed', 'An error occurred while deleting the record', array('status' => 500));
        }
    }
    
    public function bulk_delete_feeding_records($request) {
        try {
            $user_id = get_current_user_id();
            $start_date = sanitize_text_field($request['start_date']);
            $end_date = sanitize_text_field($request['end_date']);
            $exclude_active_kittens = isset($request['exclude_active_kittens']) ? (bool)$request['exclude_active_kittens'] : true;
            
            // Validate date format
            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $start_date) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $end_date)) {
                return new WP_Error('invalid_date_format', 'Invalid date format. Use YYYY-MM-DD.', array('status' => 400));
            }
            
            // Validate date range
            if (strtotime($start_date) > strtotime($end_date)) {
                return new WP_Error('invalid_date_range', 'Start date must be before or equal to end date.', array('status' => 400));
            }
            
            $deleted_count = $this->database->delete_feeding_records_by_date_range($user_id, $start_date, $end_date, $exclude_active_kittens);
            
            if ($deleted_count === false) {
                return new WP_Error('delete_failed', 'Database error occurred while deleting records', array('status' => 500));
            }
            
            $protection_message = $exclude_active_kittens ? ' (records for active kittens were protected)' : '';
            
            return new WP_REST_Response(array(
                'success' => true,
                'deleted_count' => $deleted_count,
                'message' => "Successfully deleted {$deleted_count} feeding records from {$start_date} to {$end_date}{$protection_message}"
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error bulk deleting feeding records: ' . $e->getMessage(), 'error');
            return new WP_Error('delete_failed', 'An error occurred while deleting records', array('status' => 500));
        }
    }
    
    public function get_baby_kittens($request) {
        try {
            $user_id = get_current_user_id();
            $kittens = $this->database->get_baby_kittens($user_id);
            
            return new WP_REST_Response($kittens, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting baby kittens: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve baby kittens', array('status' => 500));
        }
    }
    
    public function geocode_address($request) {
        $address = $request->get_param('address');
        
        if (empty($address)) {
            return new WP_Error('missing_address', 'Address is required', array('status' => 400));
        }
        
        try {
            // Use OpenStreetMap Nominatim for free geocoding
            // Use the configured default location context if available
            $default_location = get_option('claws_default_location', 'United States');
            $encoded_address = urlencode($address . ', ' . $default_location);
            $url = "https://nominatim.openstreetmap.org/search?format=json&q={$encoded_address}&limit=1";
            
            $response = wp_remote_get($url, array(
                'timeout' => 15,
                'user-agent' => 'CLAWS-App/1.0 (' . get_site_url() . ')'
            ));
            
            if (is_wp_error($response)) {
                return new WP_Error('geocoding_failed', 'Failed to connect to geocoding service', array('status' => 500));
            }
            
            $body = wp_remote_retrieve_body($response);
            $data = json_decode($body, true);
            
            if (empty($data)) {
                return new WP_Error('address_not_found', 'Address not found', array('status' => 404));
            }
            
            $result = $data[0];
            return new WP_REST_Response(array(
                'lat' => floatval($result['lat']),
                'lng' => floatval($result['lon']),
                'display_name' => $result['display_name']
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Geocoding error: ' . $e->getMessage(), 'error');
            return new WP_Error('geocoding_failed', 'Geocoding service error', array('status' => 500));
        }
    }
    
    public function get_admin_report($request) {
        try {
            // Admin reports should show all colonies for administrators
            $user_id = current_user_can('manage_options') ? null : get_current_user_id();
            $colonies = $this->database->get_colonies($user_id);
            $total_cats = array_sum(array_column($colonies, 'cats'));
            
            $report_data = array(
                'total_colonies' => count($colonies),
                'total_cats' => $total_cats,
                'total_intakes' => wp_count_posts('claws_intake')->publish,
                'total_discharges' => wp_count_posts('claws_discharge')->publish,
                'active_users' => count(get_users()),
                'colonies' => array_slice($colonies, 0, 10), // Top 10 colonies
                'recent_activity' => $this->get_recent_activity()
            );
            
            return new WP_REST_Response($report_data, 200);
            
        } catch (Exception $e) {
            claws_log('Error generating admin report: ' . $e->getMessage(), 'error');
            return new WP_Error('report_failed', 'Could not generate admin report', array('status' => 500));
        }
    }
    
    /**
     * Get recent activity across all post types
     */
    private function get_recent_activity() {
        $recent_posts = get_posts(array(
            'post_type' => array('claws_colony', 'claws_intake', 'claws_discharge'),
            'numberposts' => 10,
            'post_status' => 'publish',
            'orderby' => 'date',
            'order' => 'DESC'
        ));
        
        $activity = array();
        foreach ($recent_posts as $post) {
            $user = get_userdata($post->post_author);
            $activity[] = array(
                'type' => str_replace('claws_', '', $post->post_type),
                'title' => $post->post_title,
                'author' => $user ? $user->display_name : 'Unknown',
                'date' => $post->post_date
            );
        }
        
        return $activity;
    }
    
    /**
     * Get all intake records for admin charts and detailed display
     */
    public function get_all_intakes($request) {
        try {
            $intakes = get_posts(array(
                'post_type' => 'claws_intake',
                'numberposts' => -1,
                'post_status' => 'publish'
            ));
            
            $intake_data = array();
            foreach ($intakes as $intake) {
                // NOTE:
                // Admins/editors can see all intake posts. The front-end editor relies on the
                // full meta payload (including contact_* fields, fiv, special_needs, etc.).
                // Previously this endpoint returned a partial subset, which made the edit
                // modal look like the "top half" was missing and caused checkbox fields
                // (e.g. FIV) to appear unchecked.
                $meta = get_post_meta($intake->ID);

                // Get author information
                $author_info = get_userdata($intake->post_author);
                $author_name = $author_info ? $author_info->display_name : 'Unknown';

                // Start with basic fields
                $intake_info = array(
                    'id' => $intake->ID,
                    'title' => $intake->post_title,
                    'date' => $intake->post_date,
                    'author' => $intake->post_author,
                    'user_id' => $intake->post_author, // Alias for compatibility
                    'author_name' => $author_name,
                );

                // Add ALL meta fields (mirrors get_user_intakes)
                foreach ($meta as $key => $value) {
                    $intake_info[$key] = is_array($value) ? $value[0] : $value;
                }

                // Ensure common aliases exist for older UI code paths
                if (!isset($intake_info['cat_name']) && isset($intake_info['name'])) {
                    $intake_info['cat_name'] = $intake_info['name'];
                }
                if (!isset($intake_info['name']) && isset($intake_info['cat_name'])) {
                    $intake_info['name'] = $intake_info['cat_name'];
                }
                if (!isset($intake_info['intake_date']) && isset($intake_info['date'])) {
                    $intake_info['intake_date'] = $intake_info['date'];
                }
                if (!isset($intake_info['date']) && isset($intake_info['intake_date'])) {
                    $intake_info['date'] = $intake_info['intake_date'];
                }

                $intake_data[] = $intake_info;
            }
            
            return new WP_REST_Response($intake_data, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting all intakes: ' . $e->getMessage(), 'error');
            return new WP_Error('intakes_failed', 'Could not get intake data', array('status' => 500));
        }
    }
    
    /**
     * Get all discharge records for admin charts
     */
    public function get_all_discharges($request) {
        try {
            $discharges = get_posts(array(
                'post_type' => 'claws_discharge',
                'numberposts' => -1,
                'post_status' => 'publish'
            ));
            
            $discharge_data = array();
            foreach ($discharges as $discharge) {
                $meta = get_post_meta($discharge->ID);

                // Get author information
                $author_info = get_userdata($discharge->post_author);
                $author_name = $author_info ? $author_info->display_name : 'Unknown';

                // Start with basic fields
                $discharge_info = array(
                    'id' => $discharge->ID,
                    'title' => $discharge->post_title,
                    'date' => $discharge->post_date,
                    'author' => $discharge->post_author,
                    'user_id' => $discharge->post_author, // Alias for compatibility
                    'author_name' => $author_name,
                    'added_by_name' => $author_name,
                );

                // Add ALL meta fields (mirrors get_user_discharges)
                foreach ($meta as $key => $value) {
                    $discharge_info[$key] = is_array($value) ? $value[0] : $value;
                }

                // Ensure cat name exists (some historical records stored it only in post title)
                if (empty($discharge_info['cat_name']) && !empty($discharge->post_title)) {
                    $title_parts = explode(' - ', $discharge->post_title);
                    if (!empty($title_parts[0])) {
                        $discharge_info['cat_name'] = $title_parts[0];
                    }
                }

                // Alias for older UI code paths
                if (!isset($discharge_info['name']) && isset($discharge_info['cat_name'])) {
                    $discharge_info['name'] = $discharge_info['cat_name'];
                }
                if (!isset($discharge_info['discharge_date']) && isset($discharge_info['date'])) {
                    $discharge_info['discharge_date'] = $discharge_info['date'];
                }
                if (!isset($discharge_info['date']) && isset($discharge_info['discharge_date'])) {
                    $discharge_info['date'] = $discharge_info['discharge_date'];
                }
                $discharge_data[] = $discharge_info;
            }
            
            return new WP_REST_Response($discharge_data, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting all discharges: ' . $e->getMessage(), 'error');
            return new WP_Error('discharges_failed', 'Could not get discharge data', array('status' => 500));
        }
    }
    
    /**
     * Upload photo for colony
     */
    public function upload_colony_photo($request) {
        $colony_id = absint($request['id']);
        
        // Verify colony exists and user can edit it
        $colony = get_post($colony_id);
        if (!$colony || $colony->post_type !== 'claws_colony') {
            return new WP_Error('invalid_colony', 'Colony not found', array('status' => 404));
        }
        
        // Check permissions (admins can edit any colony, others only their own)
        if (!current_user_can('manage_options') && $colony->post_author != get_current_user_id()) {
            return new WP_Error('permission_denied', 'You cannot upload photos to this colony', array('status' => 403));
        }
        
        return $this->handle_photo_upload('colony', $colony_id);
    }
    
    /**
     * Upload photo for intake record
     */
    public function upload_intake_photo($request) {
        $intake_id = absint($request['id']);
        
        // Verify intake exists and belongs to user
        $intake = get_post($intake_id);
        if (!$intake || $intake->post_type !== 'claws_intake') {
            return new WP_Error('invalid_intake', 'Intake record not found', array('status' => 404));
        }
        
        // User can only upload photos to their own intake records
        if ($intake->post_author != get_current_user_id()) {
            return new WP_Error('permission_denied', 'You cannot upload photos to this intake record', array('status' => 403));
        }
        
        return $this->handle_photo_upload('intake', $intake_id);
    }
    
    /**
     * Upload photo for discharge record
     */
    public function upload_discharge_photo($request) {
        $discharge_id = absint($request['id']);
        
        // Verify discharge exists and belongs to user
        $discharge = get_post($discharge_id);
        if (!$discharge || $discharge->post_type !== 'claws_discharge') {
            return new WP_Error('invalid_discharge', 'Discharge record not found', array('status' => 404));
        }
        
        // User can only upload photos to their own discharge records
        if ($discharge->post_author != get_current_user_id()) {
            return new WP_Error('permission_denied', 'You cannot upload photos to this discharge record', array('status' => 403));
        }
        
        return $this->handle_photo_upload('discharge', $discharge_id);
    }
    
    /**
     * Handle photo upload for any record type
     */
    private function handle_photo_upload($type, $record_id) {
        // Check if file was uploaded
        if (empty($_FILES['photo'])) {
            return new WP_Error('no_file', 'No photo file uploaded', array('status' => 400));
        }
        
        $file = $_FILES['photo'];
        
        // Validate file
        $allowed_types = array('image/jpeg', 'image/png', 'image/webp');
        if (!in_array($file['type'], $allowed_types)) {
            return new WP_Error('invalid_type', 'Only JPG, PNG, and WebP images are allowed', array('status' => 400));
        }
        
        // Check file size (5MB max)
        $max_size = 5 * 1024 * 1024; // 5MB in bytes
        if ($file['size'] > $max_size) {
            return new WP_Error('file_too_large', 'File size must be under 5MB', array('status' => 400));
        }
        
        // Include WordPress file handling functions
        if (!function_exists('wp_handle_upload')) {
            require_once(ABSPATH . 'wp-admin/includes/file.php');
        }
        
        // Configure upload settings
        $upload_overrides = array(
            'test_form' => false,
            'mimes' => array(
                'jpg|jpeg|jpe' => 'image/jpeg',
                'png' => 'image/png',
                'webp' => 'image/webp',
            )
        );
        
        // Handle the upload
        $uploaded_file = wp_handle_upload($file, $upload_overrides);
        
        if (isset($uploaded_file['error'])) {
            return new WP_Error('upload_error', $uploaded_file['error'], array('status' => 500));
        }
        
        // Create WordPress attachment
        $attachment = array(
            'post_mime_type' => $uploaded_file['type'],
            'post_title' => sanitize_file_name(pathinfo($uploaded_file['file'], PATHINFO_FILENAME)),
            'post_content' => '',
            'post_status' => 'inherit'
        );
        
        $attachment_id = wp_insert_attachment($attachment, $uploaded_file['file'], $record_id);
        
        if (is_wp_error($attachment_id)) {
            return new WP_Error('attachment_error', 'Could not create attachment', array('status' => 500));
        }
        
        // Generate attachment metadata
        if (!function_exists('wp_generate_attachment_metadata')) {
            require_once(ABSPATH . 'wp-admin/includes/image.php');
        }
        
        $attachment_data = wp_generate_attachment_metadata($attachment_id, $uploaded_file['file']);
        wp_update_attachment_metadata($attachment_id, $attachment_data);
        
        // Store photo reference based on type
        $this->store_photo_reference($type, $record_id, $attachment_id);
        
        // Return success response with photo info
        return new WP_REST_Response(array(
            'success' => true,
            'attachment_id' => $attachment_id,
            'url' => wp_get_attachment_url($attachment_id),
            'thumbnail' => wp_get_attachment_thumb_url($attachment_id),
            'message' => 'Photo uploaded successfully'
        ), 200);
    }
    
    /**
     * Store photo reference in post meta
     */
    private function store_photo_reference($type, $record_id, $attachment_id) {
        switch ($type) {
            case 'colony':
                // Colonies can have multiple photos - store as array
                $existing_photos = get_post_meta($record_id, 'colony_photos', true);
                if (!is_array($existing_photos)) {
                    $existing_photos = array();
                }
                $existing_photos[] = $attachment_id;
                update_post_meta($record_id, 'colony_photos', $existing_photos);
                break;
                
            case 'intake':
                // Intake records have single photo
                update_post_meta($record_id, 'intake_photo', $attachment_id);
                break;
                
            case 'discharge':
                // Discharge records have single photo
                update_post_meta($record_id, 'discharge_photo', $attachment_id);
                break;
        }
        
        claws_log("Photo uploaded for {$type} record {$record_id}: attachment {$attachment_id}");
    }
    
    /**
     * Get colony historical records
     */
    public function get_colony_history($request) {
        try {
            $colony_id = absint($request['id']);
            $user_id = get_current_user_id();
            
            // Use new custom post type method instead of custom table
            $history = $this->database->get_colony_history_posts($colony_id, $user_id);
            
            return new WP_REST_Response($history, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting colony history: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve colony history', array('status' => 500));
        }
    }
    
    /**
     * Track feature usage for analytics
     */
    public function track_feature_usage($request) {
        try {
            $feature = sanitize_text_field($request['feature']);
            $action = sanitize_text_field($request['action']);
            $timestamp = sanitize_text_field($request['timestamp']);
            $user_id = get_current_user_id();
            
            // Get user's current plan
            $plan = 'unknown';
            $is_trial = false;
            $plan = 'free';
            
            // Log to WordPress options for simple analytics
            $analytics_data = get_option('claws_feature_analytics', array());
            
            $analytics_entry = array(
                'user_id' => $user_id,
                'feature' => $feature,
                'action' => $action,
                'plan' => $plan,
                'is_trial' => $is_trial,
                'timestamp' => $timestamp,
                'date' => current_time('mysql')
            );
            
            // Add to array (keep last 1000 entries)
            $analytics_data[] = $analytics_entry;
            if (count($analytics_data) > 1000) {
                $analytics_data = array_slice($analytics_data, -1000);
            }
            
            update_option('claws_feature_analytics', $analytics_data, false);
            
            return new WP_REST_Response(array('success' => true), 200);
            
        } catch (Exception $e) {
            // Fail silently - don't disrupt user experience
            claws_log('Analytics tracking error: ' . $e->getMessage(), 'debug');
            return new WP_REST_Response(array('success' => false), 200);
        }
    }
    
    /**
     * Get list of coordinators (editors and admins) for task approval
     * Excludes the current logged-in user (can't approve own tasks)
     */
    public function get_coordinators($request) {
        try {
            $current_user_id = get_current_user_id();
            
            // Get all users with editor or administrator role
            $coordinators = get_users(array(
                'role__in' => array('editor', 'administrator'),
                'orderby' => 'display_name',
                'order' => 'ASC'
            ));
            
            $coordinator_list = array();
            
            foreach ($coordinators as $coordinator) {
                // Skip current user - can't approve own tasks
                if ($coordinator->ID == $current_user_id) {
                    continue;
                }
                
                $coordinator_list[] = array(
                    'id' => $coordinator->ID,
                    'name' => $coordinator->display_name,
                    'email' => $coordinator->user_email,
                    'role' => $this->get_primary_role($coordinator)
                );
            }
            
            return new WP_REST_Response($coordinator_list, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting coordinators: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve coordinators', array('status' => 500));
        }
    }
    
    /**
     * Get the primary role of a user
     */
    private function get_primary_role($user) {
        $roles = $user->roles;
        if (in_array('administrator', $roles)) {
            return 'Administrator';
        } elseif (in_array('editor', $roles)) {
            return 'Editor';
        }
        return 'User';
    }
    
    /**
     * Get all volunteers for event spot reservations
     */
    public function get_all_volunteers($request) {
        try {
            // Get all users regardless of role
            $volunteers = get_users(array(
                'orderby' => 'display_name',
                'order' => 'ASC'
            ));
            
            $volunteer_list = array();
            
            foreach ($volunteers as $volunteer) {
                // Check if user is online (transient exists and hasn't expired)
                $is_online = get_transient('claws_user_online_' . $volunteer->ID) !== false;
                
                $volunteer_list[] = array(
                    'id' => $volunteer->ID,
                    'name' => $volunteer->display_name,
                    'email' => $volunteer->user_email,
                    'is_online' => $is_online
                );
            }
            
            return new WP_REST_Response($volunteer_list, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting volunteers: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve volunteers', array('status' => 500));
        }
    }
    
    /**
     * Create a new event with volunteer spots
     */
    public function create_event($request) {
        try {
            $params = $request->get_json_params();
            $current_user_id = get_current_user_id();
            
            // Validate required fields
            if (empty($params['name']) || empty($params['date'])) {
                return new WP_Error('missing_fields', 'Event name and date are required', array('status' => 400));
            }
            
            // Create event post
            $event_post = array(
                'post_title' => sanitize_text_field($params['name']),
                'post_type' => 'claws_event',
                'post_status' => 'publish',
                'post_author' => $current_user_id,
            );
            
            $event_id = wp_insert_post($event_post);
            
            if (is_wp_error($event_id)) {
                return new WP_Error('create_failed', 'Failed to create event', array('status' => 500));
            }
            
            // Save event metadata
            update_post_meta($event_id, 'type', sanitize_text_field($params['type'] ?? 'event')); // event or project
            update_post_meta($event_id, 'category', sanitize_text_field($params['category'] ?? ''));
            update_post_meta($event_id, 'colony_id', absint($params['colony'] ?? 0));
            update_post_meta($event_id, 'event_date', sanitize_text_field($params['date']));
            update_post_meta($event_id, 'start_time', sanitize_text_field($params['startTime'] ?? ''));
            update_post_meta($event_id, 'end_time', sanitize_text_field($params['endTime'] ?? ''));
            update_post_meta($event_id, 'min_commitment', sanitize_text_field($params['minCommitment'] ?? ''));
            update_post_meta($event_id, 'coordinator_name', sanitize_text_field($params['coordinator'] ?? ''));
            update_post_meta($event_id, 'coordinator_email', sanitize_email($params['email'] ?? ''));
            update_post_meta($event_id, 'coordinator_phone', sanitize_text_field($params['phone'] ?? ''));
            update_post_meta($event_id, 'coordinator_id', $current_user_id);
            update_post_meta($event_id, 'lead_id', absint($params['leadId'] ?? 0)); // Event lead
            update_post_meta($event_id, 'notes', sanitize_textarea_field($params['notes'] ?? ''));
            update_post_meta($event_id, 'num_volunteers', absint($params['numVolunteers'] ?? 1));
            update_post_meta($event_id, 'status', 'upcoming');
            
            // Save address if provided
            if (!empty($params['address'])) {
                update_post_meta($event_id, 'address_street', sanitize_text_field($params['address']['street'] ?? ''));
                update_post_meta($event_id, 'address_city', sanitize_text_field($params['address']['city'] ?? ''));
                update_post_meta($event_id, 'address_state', sanitize_text_field($params['address']['state'] ?? ''));
                update_post_meta($event_id, 'address_zip', sanitize_text_field($params['address']['zip'] ?? ''));
            }
            
            // Save volunteer spots
            $spots_data = array();
            $reserved_volunteers = array();
            
            if (!empty($params['volunteerSpots'])) {
                foreach ($params['volunteerSpots'] as $spot) {
                    $spot_data = array(
                        'spot_number' => absint($spot['spotNumber']),
                        'volunteer_id' => absint($spot['volunteerId'] ?? 0),
                        'reserved' => (bool)($spot['reserved'] ?? false),
                        'confirmed' => false,
                        'status' => 'open'
                    );
                    
                    // Track reserved volunteers for email
                    if ($spot_data['reserved'] && $spot_data['volunteer_id']) {
                        $spot_data['status'] = 'reserved';
                        $reserved_volunteers[] = $spot_data['volunteer_id'];
                    }
                    
                    $spots_data[] = $spot_data;
                }
            }
            
            update_post_meta($event_id, 'volunteer_spots', $spots_data);
            
            // Send emails
            $event_name = $params['name'];
            $event_date = date('F j, Y', strtotime($params['date']));
            $event_time = '';
            if (!empty($params['startTime']) && !empty($params['endTime'])) {
                $event_time = date('g:i A', strtotime($params['startTime'])) . ' - ' . 
                              date('g:i A', strtotime($params['endTime']));
            }
            
            // Send general notification to all volunteers
            $this->send_new_event_email($event_name, $event_date, $event_time);
            
            // Send reservation emails to reserved volunteers
            foreach ($reserved_volunteers as $volunteer_id) {
                $this->send_reservation_email(
                    $volunteer_id,
                    $event_name,
                    $event_date,
                    $event_time,
                    $params['coordinator'] ?? ''
                );
            }
            
            return new WP_REST_Response(array(
                'success' => true,
                'event_id' => $event_id,
                'message' => 'Event created successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error creating event: ' . $e->getMessage(), 'error');
            return new WP_Error('create_failed', 'Failed to create event', array('status' => 500));
        }
    }
    
    /**
     * Decline event reservation
     */
    public function decline_event_reservation($request) {
        try {
            $event_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $decline_note = sanitize_textarea_field($request->get_param('note') ?? '');
            
            // Get event spots
            $spots = get_post_meta($event_id, 'volunteer_spots', true);
            
            if (!is_array($spots)) {
                return new WP_Error('not_found', 'Event not found', array('status' => 404));
            }
            
            $updated = false;
            $coordinator_id = get_post_meta($event_id, 'coordinator_id', true);
            $event_name = get_the_title($event_id);
            $volunteer_name = '';
            
            // Find and update the spot
            foreach ($spots as &$spot) {
                if ($spot['volunteer_id'] == $current_user_id && $spot['reserved']) {
                    $volunteer = get_user_by('ID', $current_user_id);
                    $volunteer_name = $volunteer->display_name;
                    
                    // Clear the reservation
                    $spot['volunteer_id'] = 0;
                    $spot['reserved'] = false;
                    $spot['confirmed'] = false;
                    $spot['status'] = 'open';
                    $updated = true;
                    break;
                }
            }
            
            if ($updated) {
                update_post_meta($event_id, 'volunteer_spots', $spots);
                
                // Send notification to coordinator
                $this->send_decline_notification($coordinator_id, $volunteer_name, $event_name, $decline_note);
                
                return new WP_REST_Response(array(
                    'success' => true,
                    'message' => 'Reservation declined successfully'
                ), 200);
            }
            
            return new WP_Error('not_found', 'Reservation not found', array('status' => 404));
            
        } catch (Exception $e) {
            claws_log('Error declining reservation: ' . $e->getMessage(), 'error');
            return new WP_Error('decline_failed', 'Failed to decline reservation', array('status' => 500));
        }
    }
    
    /**
     * Confirm event reservation
     */
    public function confirm_event_reservation($request) {
        try {
            $event_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            
            // Get event spots
            $spots = get_post_meta($event_id, 'volunteer_spots', true);
            
            if (!is_array($spots)) {
                return new WP_Error('not_found', 'Event not found', array('status' => 404));
            }
            
            $updated = false;
            
            // Find and confirm the spot
            foreach ($spots as &$spot) {
                if ($spot['volunteer_id'] == $current_user_id && $spot['reserved']) {
                    $spot['confirmed'] = true;
                    $spot['status'] = 'confirmed';
                    $updated = true;
                    break;
                }
            }
            
            if ($updated) {
                update_post_meta($event_id, 'volunteer_spots', $spots);
                
                return new WP_REST_Response(array(
                    'success' => true,
                    'message' => 'Reservation confirmed successfully'
                ), 200);
            }
            
            return new WP_Error('not_found', 'Reservation not found', array('status' => 404));
            
        } catch (Exception $e) {
            claws_log('Error confirming reservation: ' . $e->getMessage(), 'error');
            return new WP_Error('confirm_failed', 'Failed to confirm reservation', array('status' => 500));
        }
    }
    
    /**
     * Claim an event spot for the current user
     */
    public function claim_event_spot($request) {
        try {
            $event_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            if (!$spot_number) {
                return new WP_Error('invalid_spot', 'Invalid spot number', array('status' => 400));
            }
            
            // Get event spots
            $spots = get_post_meta($event_id, 'volunteer_spots', true);
            
            if (!is_array($spots)) {
                return new WP_Error('not_found', 'Event not found', array('status' => 404));
            }
            
            // Find the spot (array is 0-indexed, spot numbers are 1-indexed)
            $spot_index = $spot_number - 1;
            
            if (!isset($spots[$spot_index])) {
                return new WP_Error('spot_not_found', 'Spot not found', array('status' => 404));
            }
            
            // Check if already reserved
            if ($spots[$spot_index]['reserved']) {
                return new WP_Error('already_reserved', 'This spot is already reserved', array('status' => 400));
            }
            
            // Claim the spot
            $spots[$spot_index]['volunteer_id'] = $current_user_id;
            $spots[$spot_index]['reserved'] = true;
            $spots[$spot_index]['status'] = 'reserved';
            
            update_post_meta($event_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array(
                'success' => true,
                'message' => 'Spot claimed successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error claiming spot: ' . $e->getMessage(), 'error');
            return new WP_Error('claim_failed', 'Failed to claim spot', array('status' => 500));
        }
    }
    
    /**
     * Claim a project spot for the current user
     */
    public function claim_project_spot($request) {
        try {
            $project_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            if (!$spot_number) {
                return new WP_Error('invalid_spot', 'Invalid spot number', array('status' => 400));
            }
            
            // Get project spots
            $spots = get_post_meta($project_id, 'volunteer_spots', true);
            
            if (!is_array($spots)) {
                return new WP_Error('not_found', 'Project not found', array('status' => 404));
            }
            
            // Find the spot (array is 0-indexed, spot numbers are 1-indexed)
            $spot_index = $spot_number - 1;
            
            if (!isset($spots[$spot_index])) {
                return new WP_Error('spot_not_found', 'Spot not found', array('status' => 404));
            }
            
            // Check if already reserved
            if ($spots[$spot_index]['reserved']) {
                return new WP_Error('already_reserved', 'This spot is already reserved', array('status' => 400));
            }
            
            // Claim the spot
            $spots[$spot_index]['volunteer_id'] = $current_user_id;
            $spots[$spot_index]['reserved'] = true;
            $spots[$spot_index]['status'] = 'reserved';
            
            update_post_meta($project_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array(
                'success' => true,
                'message' => 'Spot claimed successfully'
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error claiming spot: ' . $e->getMessage(), 'error');
            return new WP_Error('claim_failed', 'Failed to claim spot', array('status' => 500));
        }
    }
    
    /**
     * Unclaim an event spot (Changed My Mind)
     */
    public function unclaim_event_spot($request) {
        try {
            $event_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            $spots = get_post_meta($event_id, 'volunteer_spots', true);
            $spot_index = $spot_number - 1;
            
            // Verify this user claimed this spot
            if ($spots[$spot_index]['volunteer_id'] != $current_user_id) {
                return new WP_Error('unauthorized', 'You did not claim this spot', array('status' => 403));
            }
            
            // Unclaim the spot
            $spots[$spot_index]['volunteer_id'] = 0;
            $spots[$spot_index]['reserved'] = false;
            $spots[$spot_index]['status'] = 'open';
            
            update_post_meta($event_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('unclaim_failed', 'Failed to unclaim spot', array('status' => 500));
        }
    }
    
    /**
     * Decline a reserved event spot (makes it available to everyone)
     */
    public function decline_event_spot($request) {
        try {
            $event_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            $spots = get_post_meta($event_id, 'volunteer_spots', true);
            $spot_index = $spot_number - 1;
            
            // Verify this spot was reserved for current user
            if ($spots[$spot_index]['volunteer_id'] != $current_user_id) {
                return new WP_Error('unauthorized', 'This spot was not reserved for you', array('status' => 403));
            }
            
            // Turn it into a regular open spot
            $spots[$spot_index]['volunteer_id'] = 0;
            $spots[$spot_index]['reserved'] = false;
            $spots[$spot_index]['status'] = 'open';
            
            update_post_meta($event_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('decline_failed', 'Failed to decline spot', array('status' => 500));
        }
    }
    
    /**
     * Unclaim a project spot
     */
    public function unclaim_project_spot($request) {
        try {
            $project_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            $spots = get_post_meta($project_id, 'volunteer_spots', true);
            $spot_index = $spot_number - 1;
            
            if ($spots[$spot_index]['volunteer_id'] != $current_user_id) {
                return new WP_Error('unauthorized', 'You did not claim this spot', array('status' => 403));
            }
            
            $spots[$spot_index]['volunteer_id'] = 0;
            $spots[$spot_index]['reserved'] = false;
            $spots[$spot_index]['status'] = 'open';
            
            update_post_meta($project_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('unclaim_failed', 'Failed to unclaim spot', array('status' => 500));
        }
    }
    
    /**
     * Decline a reserved project spot
     */
    public function decline_project_spot($request) {
        try {
            $project_id = absint($request['id']);
            $current_user_id = get_current_user_id();
            $params = $request->get_json_params();
            $spot_number = absint($params['spotNumber'] ?? 0);
            
            $spots = get_post_meta($project_id, 'volunteer_spots', true);
            $spot_index = $spot_number - 1;
            
            if ($spots[$spot_index]['volunteer_id'] != $current_user_id) {
                return new WP_Error('unauthorized', 'This spot was not reserved for you', array('status' => 403));
            }
            
            $spots[$spot_index]['volunteer_id'] = 0;
            $spots[$spot_index]['reserved'] = false;
            $spots[$spot_index]['status'] = 'open';
            
            update_post_meta($project_id, 'volunteer_spots', $spots);
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('decline_failed', 'Failed to decline spot', array('status' => 500));
        }
    }
    
    /**
     * Get a single event/project for editing
     */
    public function get_event($request) {
        $event_id = absint($request['id']);
        
        $event = array(
            'id' => $event_id,
            'name' => get_the_title($event_id),
            'type' => get_post_meta($event_id, 'type', true),
            'category' => get_post_meta($event_id, 'category', true),
            'date' => get_post_meta($event_id, 'event_date', true),
            'start_time' => get_post_meta($event_id, 'start_time', true),
            'end_time' => get_post_meta($event_id, 'end_time', true),
            'min_commitment' => get_post_meta($event_id, 'min_commitment', true),
            'num_volunteers' => intval(get_post_meta($event_id, 'num_volunteers', true)),
            'lead_id' => intval(get_post_meta($event_id, 'lead_id', true)),
            'coordinator_id' => intval(get_post_meta($event_id, 'coordinator_id', true)),
            'notes' => get_post_meta($event_id, 'notes', true),
            'volunteer_spots' => get_post_meta($event_id, 'volunteer_spots', true)
        );
        
        return new WP_REST_Response($event, 200);
    }
    
    /**
     * Update an event/project
     */
    public function update_event($request) {
        $event_id = absint($request['id']);
        $params = $request->get_json_params();
        $current_user_id = get_current_user_id();
        
        // Check permissions (must be admin/editor)
        if (!current_user_can('manage_options') && !current_user_can('edit_others_posts')) {
            return new WP_Error('unauthorized', 'You do not have permission to edit events', array('status' => 403));
        }
        
        // Update post title
        wp_update_post(array(
            'ID' => $event_id,
            'post_title' => sanitize_text_field($params['name'])
        ));
        
        // Update metadata
        update_post_meta($event_id, 'type', sanitize_text_field($params['type'] ?? 'event'));
        update_post_meta($event_id, 'category', sanitize_text_field($params['category'] ?? ''));
        update_post_meta($event_id, 'event_date', sanitize_text_field($params['date']));
        update_post_meta($event_id, 'start_time', sanitize_text_field($params['startTime'] ?? ''));
        update_post_meta($event_id, 'end_time', sanitize_text_field($params['endTime'] ?? ''));
        update_post_meta($event_id, 'min_commitment', sanitize_text_field($params['minCommitment'] ?? ''));
        update_post_meta($event_id, 'lead_id', absint($params['leadId'] ?? 0));
        update_post_meta($event_id, 'notes', sanitize_textarea_field($params['notes'] ?? ''));
        update_post_meta($event_id, 'num_volunteers', absint($params['numVolunteers'] ?? 1));
        
        return new WP_REST_Response(array('success' => true, 'id' => $event_id), 200);
    }
    
    /**
     * Delete an event/project
     */
    public function delete_event($request) {
        $event_id = absint($request['id']);
        
        // Check permissions
        if (!current_user_can('manage_options') && !current_user_can('edit_others_posts')) {
            return new WP_Error('unauthorized', 'You do not have permission to delete events', array('status' => 403));
        }
        
        $result = wp_delete_post($event_id, true);
        
        if (!$result) {
            return new WP_Error('delete_failed', 'Failed to delete event', array('status' => 500));
        }
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Get a single project
     */
    public function get_project($request) {
        $project_id = absint($request['id']);
        
        $project = array(
            'id' => $project_id,
            'name' => get_the_title($project_id),
            'type' => get_post_meta($project_id, 'type', true),
            'category' => get_post_meta($project_id, 'category', true),
            'min_commitment' => get_post_meta($project_id, 'min_commitment', true),
            'num_volunteers' => intval(get_post_meta($project_id, 'num_volunteers', true)),
            'lead_id' => intval(get_post_meta($project_id, 'lead_id', true)),
            'coordinator_id' => intval(get_post_meta($project_id, 'coordinator_id', true)),
            'notes' => get_post_meta($project_id, 'notes', true),
            'volunteer_spots' => get_post_meta($project_id, 'volunteer_spots', true)
        );
        
        return new WP_REST_Response($project, 200);
    }
    
    /**
     * Update a project
     */
    public function update_project($request) {
        $project_id = absint($request['id']);
        $params = $request->get_json_params();
        
        // Check permissions (must be admin/editor)
        if (!current_user_can('manage_options') && !current_user_can('edit_others_posts')) {
            return new WP_Error('unauthorized', 'You do not have permission to edit projects', array('status' => 403));
        }
        
        // Update post title
        wp_update_post(array(
            'ID' => $project_id,
            'post_title' => sanitize_text_field($params['name'])
        ));
        
        // Update metadata (projects don't have dates/times)
        update_post_meta($project_id, 'type', 'project');
        update_post_meta($project_id, 'category', sanitize_text_field($params['category'] ?? ''));
        update_post_meta($project_id, 'min_commitment', sanitize_text_field($params['minCommitment'] ?? ''));
        update_post_meta($project_id, 'lead_id', absint($params['leadId'] ?? 0));
        update_post_meta($project_id, 'notes', sanitize_textarea_field($params['notes'] ?? ''));
        update_post_meta($project_id, 'num_volunteers', absint($params['numVolunteers'] ?? 1));
        
        return new WP_REST_Response(array('success' => true, 'id' => $project_id), 200);
    }
    
    /**
     * Retire a project (requires reason)
     */
    public function retire_project($request) {
        $project_id = absint($request['id']);
        $params = $request->get_json_params();
        $reason = sanitize_textarea_field($params['reason'] ?? '');
        
        // Check permissions
        if (!current_user_can('manage_options') && !current_user_can('edit_others_posts')) {
            return new WP_Error('unauthorized', 'You do not have permission to retire projects', array('status' => 403));
        }
        
        // Validate reason is provided
        if (empty($reason)) {
            return new WP_Error('missing_reason', 'A reason is required to retire a project', array('status' => 400));
        }
        
        // Mark as retired
        update_post_meta($project_id, 'retired', '1');
        update_post_meta($project_id, 'retired_reason', $reason);
        update_post_meta($project_id, 'retired_by', get_current_user_id());
        update_post_meta($project_id, 'retired_at', current_time('mysql'));
        
        return new WP_REST_Response(array('success' => true), 200);
    }
    
    /**
     * Send email notification for new event created
     */
    private function send_new_event_email($event_name, $event_date, $event_time) {
        // Get all volunteers
        $volunteers = get_users();
        
        $app_url = home_url('/claws-app/');
        $site_name = get_bloginfo('name');
        
        // Get email template
        $template = get_option('claws_event_created_template', 
            'Hi {{volunteer_name}},

A new volunteer opportunity has been created!

Opportunity: {{event_name}}
Date: {{event_date}}
Time: {{event_time}}

Log in to view full details and sign up:
{{app_url}}

Thank you for being part of our volunteer community!');
        
        foreach ($volunteers as $volunteer) {
            $to = $volunteer->user_email;
            $subject = 'New Volunteer Event: ' . $event_name;
            
            // Replace placeholders
            $message = str_replace('{{volunteer_name}}', $volunteer->display_name, $template);
            $message = str_replace('{{event_name}}', $event_name, $message);
            $message = str_replace('{{event_date}}', $event_date, $message);
            $message = str_replace('{{event_time}}', $event_time ?: 'TBD', $message);
            $message = str_replace('{{app_url}}', $app_url, $message);
            $message = str_replace('{{site_name}}', $site_name, $message);
            
            // Add signature
            $message .= "\n\n---\n" . $site_name;
            
            wp_mail($to, $subject, $message);
        }
    }
    
    /**
     * Send email notification for reserved spot
     */
    private function send_reservation_email($volunteer_id, $event_name, $event_date, $event_time, $coordinator_name) {
        $volunteer = get_user_by('ID', $volunteer_id);
        
        if (!$volunteer) {
            return false;
        }
        
        $to = $volunteer->user_email;
        $subject = 'Volunteer Spot Reserved: ' . $event_name;
        
        $app_url = home_url('/claws-app/');
        $site_name = get_bloginfo('name');
        
        // Get email template
        $template = get_option('claws_spot_reserved_template',
            'Hi {{volunteer_name}},

A spot has been reserved for you on {{event_name}}.

Event Details:
- Event: {{event_name}}
- Date: {{event_date}}
- Time: {{event_time}}
- Coordinator: {{coordinator_name}}

Please log in to confirm your attendance or decline if you\'re unable to participate:
{{app_url}}

If you need to decline, you can provide a note explaining why, which will be sent to the event coordinator.

Thank you for volunteering!');
        
        // Replace placeholders
        $message = str_replace('{{volunteer_name}}', $volunteer->display_name, $template);
        $message = str_replace('{{event_name}}', $event_name, $message);
        $message = str_replace('{{event_date}}', $event_date, $message);
        $message = str_replace('{{event_time}}', $event_time ?: 'TBD', $message);
        $message = str_replace('{{coordinator_name}}', $coordinator_name ?: 'Event Coordinator', $message);
        $message = str_replace('{{app_url}}', $app_url, $message);
        $message = str_replace('{{site_name}}', $site_name, $message);
        
        // Add signature
        $message .= "\n\n---\n" . $site_name;
        
        return wp_mail($to, $subject, $message);
    }
    
    /**
     * Send email notification when volunteer declines reservation
     */
    private function send_decline_notification($coordinator_id, $volunteer_name, $event_name, $decline_note) {
        $coordinator = get_user_by('ID', $coordinator_id);
        
        if (!$coordinator) {
            return false;
        }
        
        $to = $coordinator->user_email;
        $subject = 'Volunteer Declined: ' . $event_name;
        
        $site_name = get_bloginfo('name');
        
        // Get email template
        $template = get_option('claws_reservation_declined_template',
            'Hi {{coordinator_name}},

{{volunteer_name}} has declined their reserved spot for {{event_name}}.

{{decline_note}}

The spot is now available for other volunteers to sign up.

Thank you,
{{site_name}}');
        
        // Format decline note
        $formatted_note = '';
        if ($decline_note) {
            $formatted_note = "Their message:\n---\n" . $decline_note . "\n---\n";
        }
        
        // Replace placeholders
        $message = str_replace('{{coordinator_name}}', $coordinator->display_name, $template);
        $message = str_replace('{{volunteer_name}}', $volunteer_name, $message);
        $message = str_replace('{{event_name}}', $event_name, $message);
        $message = str_replace('{{decline_note}}', $formatted_note, $message);
        $message = str_replace('{{site_name}}', $site_name, $message);
        
        return wp_mail($to, $subject, $message);
    }
    
    /**
     * Get available events (one-time opportunities with dates)
     */
    public function get_available_events($request) {
        $today = date('Y-m-d');
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'type',
                    'value' => 'event',
                    'compare' => '='
                ),
                array(
                    'key' => 'event_date',
                    'value' => '',
                    'compare' => '!='
                ),
                array(
                    'key' => 'event_date',
                    'value' => $today,
                    'compare' => '>=',
                    'type' => 'DATE'
                ),
                array(
                    'key' => 'start_time',
                    'value' => '',
                    'compare' => '!='
                )
            ),
            'orderby' => 'meta_value',
            'meta_key' => 'event_date',
            'order' => 'ASC'
        );
        
        $events = get_posts($args);
        $formatted_events = array();
        
        foreach ($events as $event) {
            $event_data = array(
                'id' => $event->ID,
                'name' => $event->post_title,
                'type' => 'event',
                'category' => get_post_meta($event->ID, 'category', true),
                'date' => get_post_meta($event->ID, 'event_date', true),
                'start_time' => get_post_meta($event->ID, 'start_time', true),
                'end_time' => get_post_meta($event->ID, 'end_time', true),
                'coordinator' => get_post_meta($event->ID, 'coordinator_name', true),
                'coordinator_id' => intval(get_post_meta($event->ID, 'coordinator_id', true)),
                'coordinator_email' => get_post_meta($event->ID, 'coordinator_email', true),
                'coordinator_phone' => get_post_meta($event->ID, 'coordinator_phone', true),
                'lead_id' => intval(get_post_meta($event->ID, 'lead_id', true)),
                'num_volunteers' => intval(get_post_meta($event->ID, 'num_volunteers', true)),
                'notes' => get_post_meta($event->ID, 'notes', true),
                'status' => get_post_meta($event->ID, 'status', true),
                'volunteer_spots' => get_post_meta($event->ID, 'volunteer_spots', true) ?: array(),
                'address' => array(
                    'street' => get_post_meta($event->ID, 'address_street', true),
                    'city' => get_post_meta($event->ID, 'address_city', true),
                    'state' => get_post_meta($event->ID, 'address_state', true),
                    'zip' => get_post_meta($event->ID, 'address_zip', true)
                )
            );
            
            $formatted_events[] = $event_data;
        }
        
        return new WP_REST_Response($formatted_events, 200);
    }
    
    /**
     * Get all events (including past events)
     */
    public function get_all_events($request) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'type',
                    'value' => 'event',
                    'compare' => '='
                )
            ),
            'orderby' => 'meta_value',
            'meta_key' => 'event_date',
            'order' => 'DESC'
        );
        
        $events = get_posts($args);
        $formatted_events = array();
        
        foreach ($events as $event) {
            $event_data = array(
                'id' => $event->ID,
                'name' => $event->post_title,
                'type' => 'event',
                'category' => get_post_meta($event->ID, 'category', true),
                'date' => get_post_meta($event->ID, 'event_date', true),
                'start_time' => get_post_meta($event->ID, 'start_time', true),
                'end_time' => get_post_meta($event->ID, 'end_time', true),
                'coordinator' => get_post_meta($event->ID, 'coordinator_name', true),
                'coordinator_id' => intval(get_post_meta($event->ID, 'coordinator_id', true)),
                'coordinator_email' => get_post_meta($event->ID, 'coordinator_email', true),
                'coordinator_phone' => get_post_meta($event->ID, 'coordinator_phone', true),
                'lead_id' => intval(get_post_meta($event->ID, 'lead_id', true)),
                'num_volunteers' => intval(get_post_meta($event->ID, 'num_volunteers', true)),
                'notes' => get_post_meta($event->ID, 'notes', true),
                'status' => get_post_meta($event->ID, 'status', true),
                'volunteer_spots' => get_post_meta($event->ID, 'volunteer_spots', true) ?: array(),
                'address' => array(
                    'street' => get_post_meta($event->ID, 'address_street', true),
                    'city' => get_post_meta($event->ID, 'address_city', true),
                    'state' => get_post_meta($event->ID, 'address_state', true),
                    'zip' => get_post_meta($event->ID, 'address_zip', true)
                )
            );
            
            $formatted_events[] = $event_data;
        }
        
        return new WP_REST_Response($formatted_events, 200);
    }
    
    /**
     * Get available projects (ongoing opportunities without end dates)
     */
    public function get_available_projects($request) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'type',
                    'value' => 'project',
                    'compare' => '='
                ),
                array(
                    'relation' => 'OR',
                    array(
                        'key' => 'retired',
                        'compare' => 'NOT EXISTS'
                    ),
                    array(
                        'key' => 'retired',
                        'value' => '1',
                        'compare' => '!='
                    )
                )
            ),
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $projects = get_posts($args);
        $formatted_projects = array();
        
        foreach ($projects as $project) {
            $project_data = array(
                'id' => $project->ID,
                'name' => $project->post_title,
                'type' => 'project',
                'category' => get_post_meta($project->ID, 'category', true),
                'min_commitment' => get_post_meta($project->ID, 'min_commitment', true),
                'coordinator' => get_post_meta($project->ID, 'coordinator_name', true),
                'coordinator_id' => intval(get_post_meta($project->ID, 'coordinator_id', true)),
                'coordinator_email' => get_post_meta($project->ID, 'coordinator_email', true),
                'coordinator_phone' => get_post_meta($project->ID, 'coordinator_phone', true),
                'lead_id' => intval(get_post_meta($project->ID, 'lead_id', true)),
                'num_volunteers' => intval(get_post_meta($project->ID, 'num_volunteers', true)),
                'notes' => get_post_meta($project->ID, 'notes', true),
                'status' => get_post_meta($project->ID, 'status', true),
                'retired' => get_post_meta($project->ID, 'retired', true),
                'volunteer_spots' => get_post_meta($project->ID, 'volunteer_spots', true) ?: array(),
                'address' => array(
                    'street' => get_post_meta($project->ID, 'address_street', true),
                    'city' => get_post_meta($project->ID, 'address_city', true),
                    'state' => get_post_meta($project->ID, 'address_state', true),
                    'zip' => get_post_meta($project->ID, 'address_zip', true)
                )
            );
            
            $formatted_projects[] = $project_data;
        }
        
        return new WP_REST_Response($formatted_projects, 200);
    }
    
    /**
     * Get all projects (including retired)
     */
    public function get_all_projects($request) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'type',
                    'value' => 'project',
                    'compare' => '='
                )
            ),
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $projects = get_posts($args);
        $formatted_projects = array();
        
        foreach ($projects as $project) {
            $project_data = array(
                'id' => $project->ID,
                'name' => $project->post_title,
                'type' => 'project',
                'category' => get_post_meta($project->ID, 'category', true),
                'colony_id' => get_post_meta($project->ID, 'colony_id', true),
                'colony_name' => get_post_meta($project->ID, 'colony_name', true),
                'min_commitment' => get_post_meta($project->ID, 'min_commitment', true),
                'coordinator' => get_post_meta($project->ID, 'coordinator_name', true),
                'coordinator_id' => intval(get_post_meta($project->ID, 'coordinator_id', true)),
                'coordinator_email' => get_post_meta($project->ID, 'coordinator_email', true),
                'coordinator_phone' => get_post_meta($project->ID, 'coordinator_phone', true),
                'lead_id' => intval(get_post_meta($project->ID, 'lead_id', true)),
                'num_volunteers' => intval(get_post_meta($project->ID, 'num_volunteers', true)),
                'notes' => get_post_meta($project->ID, 'notes', true),
                'status' => get_post_meta($project->ID, 'status', true),
                'retired' => get_post_meta($project->ID, 'retired', true),
                'retired_at' => get_post_meta($project->ID, 'retired_at', true),
                'volunteer_spots' => get_post_meta($project->ID, 'volunteer_spots', true) ?: array(),
                'address' => array(
                    'street' => get_post_meta($project->ID, 'address_street', true),
                    'city' => get_post_meta($project->ID, 'address_city', true),
                    'state' => get_post_meta($project->ID, 'address_state', true),
                    'zip' => get_post_meta($project->ID, 'address_zip', true)
                )
            );
            
            $formatted_projects[] = $project_data;
        }
        
        return new WP_REST_Response($formatted_projects, 200);
    }
    
    /**
     * Get event teams for current user
     * Admins see all teams, regular users see only teams they're part of
     */
    public function get_event_teams($request) {
        try {
            $current_user_id = get_current_user_id();
            $is_admin = current_user_can('manage_options');
            
            // Get all active events (upcoming events that haven't passed)
            $today = date('Y-m-d');
            $args = array(
                'post_type' => 'claws_event',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'type',
                        'value' => 'event',
                        'compare' => '=',
                    ),
                    array(
                        'key' => 'status',
                        'value' => 'upcoming',
                        'compare' => '=',
                    ),
                    array(
                        'key' => 'event_date',
                        'value' => $today,
                        'compare' => '>=',
                        'type' => 'DATE'
                    ),
                ),
            );
            
            $events = get_posts($args);
            $teams = array();
            
            foreach ($events as $event) {
                $event_id = $event->ID;
                $spots = get_post_meta($event_id, 'volunteer_spots', true);
                $num_volunteers = get_post_meta($event_id, 'num_volunteers', true);
                
                if (!is_array($spots)) continue;
                
                // Check if current user is in this event
                $user_in_event = false;
                $members = array();
                
                foreach ($spots as $spot) {
                    if (!empty($spot['volunteer_id'])) {
                        $volunteer = get_user_by('ID', $spot['volunteer_id']);
                        if ($volunteer) {
                            $members[] = array(
                                'id' => $volunteer->ID,
                                'name' => $volunteer->display_name,
                                'email' => $volunteer->user_email,
                                'status' => $spot['status'] ?? 'open'
                            );
                            
                            if ($spot['volunteer_id'] == $current_user_id) {
                                $user_in_event = true;
                            }
                        }
                    }
                }
                
                // Include team if: admin (sees all) OR user is part of it
                if ($is_admin || $user_in_event) {
                    $event_date = get_post_meta($event_id, 'event_date', true);
                    $start_time = get_post_meta($event_id, 'start_time', true);
                    $end_time = get_post_meta($event_id, 'end_time', true);
                    $lead_id = get_post_meta($event_id, 'lead_id', true);
                    $lead = get_user_by('ID', $lead_id);
                    
                    $teams[] = array(
                        'id' => $event_id,
                        'name' => get_the_title($event_id),
                        'type' => 'event',
                        'event_date' => $event_date ? date('F j, Y', strtotime($event_date)) : '',
                        'event_time' => ($start_time && $end_time) ? 
                            date('g:i A', strtotime($start_time)) . ' - ' . date('g:i A', strtotime($end_time)) : '',
                        'lead_id' => $lead_id,
                        'lead_name' => $lead ? $lead->display_name : 'Unknown',
                        'coordinator_id' => get_post_meta($event_id, 'coordinator_id', true),
                        'coordinator_name' => get_post_meta($event_id, 'coordinator_name', true),
                        'coordinator_email' => get_post_meta($event_id, 'coordinator_email', true),
                        'notes' => get_post_meta($event_id, 'notes', true),
                        'members' => $members,
                        'total_spots' => intval($num_volunteers) ?: count($spots)
                    );
                }
            }
            
            return new WP_REST_Response($teams, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting event teams: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve event teams', array('status' => 500));
        }
    }
    
    /**
     * Get project teams for current user
     * Admins see all teams, regular users see only teams they're part of
     */
    public function get_project_teams($request) {
        try {
            $current_user_id = get_current_user_id();
            $is_admin = current_user_can('manage_options');
            
            // Get all active projects (ongoing, not retired)
            $args = array(
                'post_type' => 'claws_event',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'type',
                        'value' => 'project',
                        'compare' => '=',
                    ),
                    array(
                        'key' => 'status',
                        'value' => array('upcoming', 'active'),
                        'compare' => 'IN',
                    ),
                    array(
                        'relation' => 'OR',
                        array(
                            'key' => 'retired',
                            'compare' => 'NOT EXISTS'
                        ),
                        array(
                            'key' => 'retired',
                            'value' => '1',
                            'compare' => '!='
                        )
                    )
                ),
            );
            
            $projects = get_posts($args);
            $teams = array();
            
            foreach ($projects as $project) {
                $project_id = $project->ID;
                $spots = get_post_meta($project_id, 'volunteer_spots', true);
                $num_volunteers = get_post_meta($project_id, 'num_volunteers', true);
                
                if (!is_array($spots)) continue;
                
                // Check if current user is in this project
                $user_in_project = false;
                $members = array();
                
                foreach ($spots as $spot) {
                    if (!empty($spot['volunteer_id'])) {
                        $volunteer = get_user_by('ID', $spot['volunteer_id']);
                        if ($volunteer) {
                            $members[] = array(
                                'id' => $volunteer->ID,
                                'name' => $volunteer->display_name,
                                'email' => $volunteer->user_email,
                                'status' => $spot['status'] ?? 'open'
                            );
                            
                            if ($spot['volunteer_id'] == $current_user_id) {
                                $user_in_project = true;
                            }
                        }
                    }
                }
                
                // Include team if: admin (sees all) OR user is part of it
                if ($is_admin || $user_in_project) {
                    $lead_id = get_post_meta($project_id, 'lead_id', true);
                    $lead = get_user_by('ID', $lead_id);
                    
                    $teams[] = array(
                        'id' => $project_id,
                        'name' => get_the_title($project_id),
                        'type' => 'project',
                        'lead_id' => $lead_id,
                        'lead_name' => $lead ? $lead->display_name : 'Unknown',
                        'coordinator_id' => get_post_meta($project_id, 'coordinator_id', true),
                        'coordinator_name' => get_post_meta($project_id, 'coordinator_name', true),
                        'coordinator_email' => get_post_meta($project_id, 'coordinator_email', true),
                        'notes' => get_post_meta($project_id, 'notes', true),
                        'members' => $members,
                        'total_spots' => intval($num_volunteers) ?: count($spots)
                    );
                }
            }
            
            return new WP_REST_Response($teams, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting project teams: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve project teams', array('status' => 500));
        }
    }
    
    /**
     * Get personal volunteer stats for current user
     */
    public function get_personal_stats($request) {
        try {
            $user_id = get_current_user_id();
            claws_log('=== GET PERSONAL STATS STARTED ===', 'info');
            claws_log('User ID: ' . $user_id, 'info');
            
            // Get approved volunteer time entries
            $time_args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'volunteer_id',
                        'value' => $user_id,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'approval_status',
                        'value' => 'approved',
                        'compare' => '='
                    )
                )
            );
            
            claws_log('Query args: ' . json_encode($time_args), 'info');
            
            $time_entries = get_posts($time_args);
            claws_log('Found ' . count($time_entries) . ' approved time entries', 'info');
            
            $hours_volunteered = 0;
            $tasks_completed = count($time_entries);
            $recent_activity = array();
            
            foreach ($time_entries as $entry) {
                $hours = get_post_meta($entry->ID, 'hours', true);
                claws_log('Entry ID ' . $entry->ID . ' - Hours: ' . $hours, 'info');
                $hours_volunteered += floatval($hours);
                
                $recent_activity[] = array(
                    'title' => get_the_title($entry->ID),
                    'date' => get_the_date('M j, Y', $entry->ID),
                    'hours' => floatval($hours),
                    'type' => 'task'
                );
            }
            
            claws_log('Total hours: ' . $hours_volunteered . ', Tasks: ' . $tasks_completed, 'info');
            
            // Sort recent activity by date
            usort($recent_activity, function($a, $b) {
                return strtotime($b['date']) - strtotime($a['date']);
            });
            
            // Get events participated in
            $events_participated = $this->count_user_participations($user_id, 'event');
            claws_log('Events participated: ' . $events_participated, 'info');
            
            // Get projects participated in
            $projects_participated = $this->count_user_participations($user_id, 'project');
            claws_log('Projects participated: ' . $projects_participated, 'info');
            
            // Calculate cat-related stats from actual intake/discharge data
            // Cats Fostered = Total intakes by this user
            $intake_args = array(
                'post_type' => 'claws_intake',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'author' => $user_id
            );
            $intakes = get_posts($intake_args);
            $cats_fostered = count($intakes);
            
            // Bottle Babies = Intakes where age = Neonate
            $bottle_babies = 0;
            foreach ($intakes as $intake) {
                $age = get_post_meta($intake->ID, 'age', true);
                if ($age === 'Neonate' || strtolower($age) === 'neonate') {
                    $bottle_babies++;
                }
            }
            
            // Adoptions Facilitated = Discharges by this user with outcome = Adoption
            $discharge_args = array(
                'post_type' => 'claws_discharge',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'author' => $user_id,
                'meta_query' => array(
                    array(
                        'key' => 'outcome',
                        'value' => 'Adoption',
                        'compare' => '='
                    )
                )
            );
            $adoptions = get_posts($discharge_args);
            $adoptions_facilitated = count($adoptions);
            
            // TNR Assists = Count of TNR-related events/tasks user participated in
            // For now, count approved volunteer time entries with 'TNR' in task description or category
            $tnr_time_args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'volunteer_id',
                        'value' => $user_id,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'approval_status',
                        'value' => 'approved',
                        'compare' => '='
                    ),
                    array(
                        'key' => 'task_category',
                        'value' => 'TNR',
                        'compare' => 'LIKE'
                    )
                )
            );
            $tnr_tasks = get_posts($tnr_time_args);
            $tnr_assists = count($tnr_tasks);
            
            // Shelter Transfers = Discharges with outcome = Transfer to no-kill shelter
            $shelter_transfer_args = array(
                'post_type' => 'claws_discharge',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'author' => $user_id,
                'meta_query' => array(
                    array(
                        'key' => 'outcome',
                        'value' => 'Transfer to no-kill shelter (for eventual adoption)',
                        'compare' => '='
                    )
                )
            );
            $shelter_transfers = get_posts($shelter_transfer_args);
            $shelter_transfers_count = count($shelter_transfers);
            
            claws_log('Calculated cat stats:', 'info');
            claws_log('  - Cats fostered (intakes): ' . $cats_fostered, 'info');
            claws_log('  - Bottle babies (neonates): ' . $bottle_babies, 'info');
            claws_log('  - Adoptions facilitated: ' . $adoptions_facilitated, 'info');
            claws_log('  - TNR assists (tasks): ' . $tnr_assists, 'info');
            claws_log('  - Shelter transfers: ' . $shelter_transfers_count, 'info');
            
            return new WP_REST_Response(array(
                'hours_volunteered' => round($hours_volunteered, 1),
                'tasks_completed' => $tasks_completed,
                'events_participated' => $events_participated,
                'projects_participated' => $projects_participated,
                'cats_fostered' => $cats_fostered,
                'bottle_babies' => $bottle_babies,
                'adoptions_facilitated' => $adoptions_facilitated,
                'tnr_assists' => $tnr_assists,
                'shelter_transfers' => $shelter_transfers_count,
                'recent_activity' => $recent_activity
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error getting personal stats: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve personal stats', array('status' => 500));
        }
    }
    
    /**
     * Get organization-wide stats (admin only)
     */
    public function get_organization_stats($request) {
        try {
            claws_log('=== GET ORGANIZATION STATS STARTED ===', 'info');
            
            // Get all approved volunteer time entries
            $time_args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'approval_status',
                        'value' => 'approved',
                        'compare' => '='
                    )
                )
            );
            
            claws_log('Query args: ' . json_encode($time_args), 'info');
            
            $all_entries = get_posts($time_args);
            claws_log('Found ' . count($all_entries) . ' approved entries', 'info');
            
            $total_hours = 0;
            $total_tasks = count($all_entries);
            
            foreach ($all_entries as $entry) {
                $hours = get_post_meta($entry->ID, 'hours', true);
                $total_hours += floatval($hours);
            }
            
            claws_log('Total hours: ' . $total_hours . ', Total tasks: ' . $total_tasks, 'info');
            
            // Get total volunteers (users with volunteer role or who have logged time)
            $volunteer_users = get_users(array('role' => 'volunteer'));
            $total_volunteers = count($volunteer_users);
            
            // Get unique volunteers who have logged time
            $active_volunteers = array();
            foreach ($all_entries as $entry) {
                $vol_id = get_post_meta($entry->ID, 'volunteer_id', true);
                if ($vol_id) {
                    $active_volunteers[$vol_id] = true;
                }
            }
            
            // Count events and projects
            $events_count = $this->count_active_opportunities('event');
            $projects_count = $this->count_active_opportunities('project');
            
            // Count active teams (events + projects with participants)
            $active_teams = $this->count_active_teams();
            
            // Calculate aggregate cat stats from actual intake/discharge data
            // Total Cats Fostered = All intakes across all users
            $all_intakes_args = array(
                'post_type' => 'claws_intake',
                'post_status' => 'publish',
                'posts_per_page' => -1
            );
            $all_intakes = get_posts($all_intakes_args);
            $total_cats_fostered = count($all_intakes);
            
            // Total Bottle Babies = All intakes where age = Neonate
            $total_bottle_babies = 0;
            foreach ($all_intakes as $intake) {
                $age = get_post_meta($intake->ID, 'age', true);
                if ($age === 'Neonate' || strtolower($age) === 'neonate') {
                    $total_bottle_babies++;
                }
            }
            
            // Total Adoptions = All discharges with outcome = Adoption
            $all_adoptions_args = array(
                'post_type' => 'claws_discharge',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'outcome',
                        'value' => 'Adoption',
                        'compare' => '='
                    )
                )
            );
            $all_adoptions = get_posts($all_adoptions_args);
            $total_adoptions = count($all_adoptions);
            
            // Total TNR Assists = Count of all TNR-related volunteer time entries
            $all_tnr_time_args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'approval_status',
                        'value' => 'approved',
                        'compare' => '='
                    ),
                    array(
                        'key' => 'task_category',
                        'value' => 'TNR',
                        'compare' => 'LIKE'
                    )
                )
            );
            $all_tnr_tasks = get_posts($all_tnr_time_args);
            $total_tnr = count($all_tnr_tasks);
            
            // Total Shelter Transfers = Discharges with outcome = Transfer to no-kill shelter
            $all_shelter_transfer_args = array(
                'post_type' => 'claws_discharge',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'outcome',
                        'value' => 'Transfer to no-kill shelter (for eventual adoption)',
                        'compare' => '='
                    )
                )
            );
            $all_shelter_transfers = get_posts($all_shelter_transfer_args);
            $total_shelter_transfers = count($all_shelter_transfers);
            
            claws_log('Calculated organization cat stats:', 'info');
            claws_log('  - Total cats fostered (intakes): ' . $total_cats_fostered, 'info');
            claws_log('  - Total bottle babies (neonates): ' . $total_bottle_babies, 'info');
            claws_log('  - Total adoptions: ' . $total_adoptions, 'info');
            claws_log('  - Total TNR assists (tasks): ' . $total_tnr, 'info');
            claws_log('  - Total shelter transfers: ' . $total_shelter_transfers, 'info');
            
            return new WP_REST_Response(array(
                'hours_volunteered' => round($total_hours, 1),
                'tasks_completed' => $total_tasks,
                'events_participated' => $events_count,
                'projects_participated' => $projects_count,
                'cats_fostered' => $total_cats_fostered,
                'bottle_babies' => $total_bottle_babies,
                'adoptions_facilitated' => $total_adoptions,
                'tnr_assists' => $total_tnr,
                'shelter_transfers' => $total_shelter_transfers,
                'total_volunteers' => $total_volunteers,
                'active_teams' => $active_teams,
                'upcoming_events' => $events_count,
                'active_projects' => $projects_count
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error getting organization stats: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve organization stats', array('status' => 500));
        }
    }
    
    /**
     * Get top volunteers by hours (admin only)
     */
    public function get_top_volunteers($request) {
        try {
            // Get all volunteer users
            $users = get_users();
            $volunteer_stats = array();
            
            foreach ($users as $user) {
                // Get approved time entries for this user
                $time_args = array(
                    'post_type' => 'claws_volunteer_time',
                    'post_status' => 'publish',
                    'posts_per_page' => -1,
                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' => 'volunteer_id',
                            'value' => $user->ID,
                            'compare' => '='
                        ),
                        array(
                            'key' => 'approval_status',
                            'value' => 'approved',
                            'compare' => '='
                        )
                    )
                );
                
                $entries = get_posts($time_args);
                if (empty($entries)) continue;
                
                $hours = 0;
                foreach ($entries as $entry) {
                    $hours += floatval(get_post_meta($entry->ID, 'hours', true));
                }
                
                $events_attended = $this->count_user_participations($user->ID, 'event');
                
                $volunteer_stats[] = array(
                    'id' => $user->ID,
                    'name' => $user->display_name,
                    'hours' => round($hours, 1),
                    'tasks_completed' => count($entries),
                    'events_attended' => $events_attended
                );
            }
            
            // Sort by hours descending
            usort($volunteer_stats, function($a, $b) {
                return $b['hours'] <=> $a['hours'];
            });
            
            // Return top 10
            return new WP_REST_Response(array_slice($volunteer_stats, 0, 10), 200);
            
        } catch (Exception $e) {
            claws_log('Error getting top volunteers: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve top volunteers', array('status' => 500));
        }
    }
    
    /**
     * Get mover & shaker - volunteer with most team memberships (admin only)
     */
    public function get_mover_shaker($request) {
        try {
            $users = get_users();
            $volunteer_teams = array();
            
            foreach ($users as $user) {
                // Count unique teams (events + projects) this user is part of
                $event_count = $this->count_user_participations($user->ID, 'event');
                $project_count = $this->count_user_participations($user->ID, 'project');
                
                // Also count teams where user is the lead
                $lead_count = $this->count_user_as_lead($user->ID);
                
                $total_teams = $event_count + $project_count + $lead_count;
                
                if ($total_teams > 0) {
                    // Get user role for tiebreaker
                    $user_roles = $user->roles;
                    $role_priority = $this->get_role_priority($user_roles);
                    
                    $volunteer_teams[] = array(
                        'id' => $user->ID,
                        'name' => $user->display_name,
                        'team_count' => $total_teams,
                        'event_count' => $event_count,
                        'project_count' => $project_count,
                        'lead_count' => $lead_count,
                        'role_priority' => $role_priority
                    );
                }
            }
            
            // Sort by team count descending, then by role priority descending (higher priority = lower rank)
            usort($volunteer_teams, function($a, $b) {
                if ($a['team_count'] !== $b['team_count']) {
                    return $b['team_count'] <=> $a['team_count'];
                }
                // Tie: higher role_priority wins (lower-ranked volunteer)
                return $b['role_priority'] <=> $a['role_priority'];
            });
            
            $mover_shaker = !empty($volunteer_teams) ? $volunteer_teams[0] : array(
                'id' => 0,
                'name' => 'No data',
                'team_count' => 0
            );
            
            return new WP_REST_Response($mover_shaker, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting mover & shaker: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve mover & shaker', array('status' => 500));
        }
    }
    
    /**
     * Count how many teams user is a lead on
     */
    private function count_user_as_lead($user_id) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'lead_id',
                    'value' => $user_id,
                    'compare' => '='
                )
            )
        );
        
        return count(get_posts($args));
    }
    
    /**
     * Get role priority for tiebreaker (higher number = lower rank = wins tie)
     */
    private function get_role_priority($roles) {
        // Priority: subscriber > contributor > author > editor > administrator
        // Higher number = lower rank = wins in tie
        $priority_map = array(
            'subscriber' => 5,
            'contributor' => 4,
            'author' => 3,
            'editor' => 2,
            'administrator' => 1
        );
        
        // Get highest priority role (lowest rank)
        $max_priority = 0;
        foreach ($roles as $role) {
            if (isset($priority_map[$role]) && $priority_map[$role] > $max_priority) {
                $max_priority = $priority_map[$role];
            }
        }
        
        return $max_priority;
    }
    
    /**
     * Get volunteer hours summary with filtering (admin only)
     */
    public function get_volunteer_hours($request) {
        try {
            $type = $request->get_param('type') ?: 'task';
            $interval = $request->get_param('interval') ?: 'none';
            
            claws_log("=== GET VOLUNTEER HOURS: type=$type, interval=$interval ===", 'info');
            
            // Calculate date range based on interval
            $date_query = $this->get_date_query_for_interval($interval);
            
            if ($type === 'task') {
                return $this->get_task_hours($date_query);
            } else {
                return $this->get_team_hours_filtered($date_query);
            }
            
        } catch (Exception $e) {
            claws_log('Error getting volunteer hours: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve volunteer hours', array('status' => 500));
        }
    }
    
    /**
     * Get date query array for time interval filtering
     */
    private function get_date_query_for_interval($interval) {
        $date_query = array();
        $now = current_time('timestamp');
        
        switch ($interval) {
            case 'current-month':
                $date_query = array(
                    'after' => date('Y-m-01', $now),
                    'before' => date('Y-m-t 23:59:59', $now),
                    'inclusive' => true
                );
                break;
                
            case 'last-month':
                $first_day_last_month = date('Y-m-01', strtotime('first day of last month', $now));
                $last_day_last_month = date('Y-m-t 23:59:59', strtotime('last day of last month', $now));
                $date_query = array(
                    'after' => $first_day_last_month,
                    'before' => $last_day_last_month,
                    'inclusive' => true
                );
                break;
                
            case 'qtd': // Quarter to Date
                $current_quarter = ceil(date('n', $now) / 3);
                $first_month_of_quarter = ($current_quarter - 1) * 3 + 1;
                $quarter_start = date('Y-' . str_pad($first_month_of_quarter, 2, '0', STR_PAD_LEFT) . '-01', $now);
                $date_query = array(
                    'after' => $quarter_start,
                    'before' => date('Y-m-d 23:59:59', $now),
                    'inclusive' => true
                );
                break;
                
            case 'last-quarter':
                $current_quarter = ceil(date('n', $now) / 3);
                $last_quarter = $current_quarter - 1;
                if ($last_quarter < 1) {
                    $last_quarter = 4;
                    $year = date('Y', $now) - 1;
                } else {
                    $year = date('Y', $now);
                }
                $first_month = ($last_quarter - 1) * 3 + 1;
                $last_month = $first_month + 2;
                $quarter_start = $year . '-' . str_pad($first_month, 2, '0', STR_PAD_LEFT) . '-01';
                $quarter_end = date('Y-m-t 23:59:59', strtotime($year . '-' . str_pad($last_month, 2, '0', STR_PAD_LEFT) . '-01'));
                $date_query = array(
                    'after' => $quarter_start,
                    'before' => $quarter_end,
                    'inclusive' => true
                );
                break;
                
            case 'ytd': // Year to Date
                $date_query = array(
                    'after' => date('Y-01-01', $now),
                    'before' => date('Y-m-d 23:59:59', $now),
                    'inclusive' => true
                );
                break;
                
            case 'last-year':
                $last_year = date('Y', $now) - 1;
                $date_query = array(
                    'after' => $last_year . '-01-01',
                    'before' => $last_year . '-12-31 23:59:59',
                    'inclusive' => true
                );
                break;
                
            case 'none':
            default:
                // No date filtering
                break;
        }
        
        return $date_query;
    }
    
    /**
     * Get task hours (all approved hours per volunteer)
     */
    private function get_task_hours($date_query) {
        $users = get_users();
        $volunteer_hours = array();
        
        foreach ($users as $user) {
            $time_args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'volunteer_id',
                        'value' => $user->ID,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'approval_status',
                        'value' => 'approved',
                        'compare' => '='
                    )
                )
            );
            
            // Add date filtering if specified
            if (!empty($date_query)) {
                $time_args['date_query'] = array($date_query);
            }
            
            $entries = get_posts($time_args);
            if (empty($entries)) continue;
            
            $hours = 0;
            foreach ($entries as $entry) {
                $hours += floatval(get_post_meta($entry->ID, 'hours', true));
            }
            
            if ($hours > 0) {
                $volunteer_hours[] = array(
                    'id' => $user->ID,
                    'name' => $user->display_name,
                    'hours' => $hours
                );
            }
        }
        
        return new WP_REST_Response(array('volunteers' => $volunteer_hours), 200);
    }
    
    /**
     * Get team hours with date filtering
     */
    private function get_team_hours_filtered($date_query) {
        $teams = array();
        
        // Get all events and projects
        $opportunities = get_posts(array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'status',
                    'value' => array('upcoming', 'active', 'completed'),
                    'compare' => 'IN'
                )
            )
        ));
        
        foreach ($opportunities as $opp) {
            $type = get_post_meta($opp->ID, 'type', true);
            $volunteer_spots = get_post_meta($opp->ID, 'volunteer_spots', true);
            $coordinator_id = get_post_meta($opp->ID, 'coordinator', true);
            
            if (!is_array($volunteer_spots)) continue;
            
            $team_volunteers = array();
            
            // Get hours for each volunteer
            foreach ($volunteer_spots as $spot) {
                if (empty($spot['volunteer_id'])) continue;
                
                $volunteer_id = $spot['volunteer_id'];
                $user = get_user_by('ID', $volunteer_id);
                if (!$user) continue;
                
                $time_args = array(
                    'post_type' => 'claws_volunteer_time',
                    'post_status' => 'publish',
                    'posts_per_page' => -1,
                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' => 'volunteer_id',
                            'value' => $volunteer_id,
                            'compare' => '='
                        ),
                        array(
                            'key' => 'approval_status',
                            'value' => 'approved',
                            'compare' => '='
                        ),
                        array(
                            'key' => 'event_id',
                            'value' => $opp->ID,
                            'compare' => '='
                        )
                    )
                );
                
                // Add date filtering
                if (!empty($date_query)) {
                    $time_args['date_query'] = array($date_query);
                }
                
                $time_entries = get_posts($time_args);
                $volunteer_hours = 0;
                
                foreach ($time_entries as $entry) {
                    $volunteer_hours += floatval(get_post_meta($entry->ID, 'hours', true));
                }
                
                if ($volunteer_hours > 0) {
                    $team_volunteers[] = array(
                        'id' => $volunteer_id,
                        'name' => $user->display_name,
                        'hours' => $volunteer_hours,
                        'is_lead' => ($volunteer_id == $coordinator_id)
                    );
                }
            }
            
            // Only include teams with logged hours
            if (!empty($team_volunteers)) {
                $teams[] = array(
                    'id' => $opp->ID,
                    'name' => get_the_title($opp->ID),
                    'type' => ucfirst($type),
                    'volunteer_count' => count($team_volunteers),
                    'volunteers' => $team_volunteers
                );
            }
        }
        
        return new WP_REST_Response(array('teams' => $teams), 200);
    }
    
    /**
     * Get team hours summary (admin only) - Legacy endpoint
     */
    public function get_team_hours($request) {
        try {
            claws_log('=== GET TEAM HOURS STARTED ===', 'info');
            
            $teams = array();
            
            // Get all events and projects
            $opportunities_args = array(
                'post_type' => 'claws_event',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'status',
                        'value' => array('upcoming', 'active', 'completed'),
                        'compare' => 'IN'
                    )
                )
            );
            
            $opportunities = get_posts($opportunities_args);
            claws_log('Found ' . count($opportunities) . ' opportunities', 'info');
            
            foreach ($opportunities as $opp) {
                $type = get_post_meta($opp->ID, 'type', true);
                $volunteer_spots = get_post_meta($opp->ID, 'volunteer_spots', true);
                
                if (!is_array($volunteer_spots)) continue;
                
                $team_volunteers = array();
                $total_team_hours = 0;
                
                // Get hours for each volunteer in this team
                foreach ($volunteer_spots as $spot) {
                    if (empty($spot['volunteer_id'])) continue;
                    
                    $volunteer_id = $spot['volunteer_id'];
                    $user = get_user_by('ID', $volunteer_id);
                    if (!$user) continue;
                    
                    // Get volunteer's hours for this specific event/project
                    $time_args = array(
                        'post_type' => 'claws_volunteer_time',
                        'post_status' => 'publish',
                        'posts_per_page' => -1,
                        'meta_query' => array(
                            'relation' => 'AND',
                            array(
                                'key' => 'volunteer_id',
                                'value' => $volunteer_id,
                                'compare' => '='
                            ),
                            array(
                                'key' => 'approval_status',
                                'value' => 'approved',
                                'compare' => '='
                            ),
                            array(
                                'key' => 'event_id',
                                'value' => $opp->ID,
                                'compare' => '='
                            )
                        )
                    );
                    
                    $time_entries = get_posts($time_args);
                    $volunteer_hours = 0;
                    
                    foreach ($time_entries as $entry) {
                        $volunteer_hours += floatval(get_post_meta($entry->ID, 'hours', true));
                    }
                    
                    if ($volunteer_hours > 0) {
                        $team_volunteers[] = array(
                            'id' => $volunteer_id,
                            'name' => $user->display_name,
                            'hours' => round($volunteer_hours, 1)
                        );
                        $total_team_hours += $volunteer_hours;
                    }
                }
                
                // Only include teams with logged hours
                if ($total_team_hours > 0) {
                    $teams[] = array(
                        'id' => $opp->ID,
                        'name' => get_the_title($opp->ID),
                        'type' => ucfirst($type),
                        'volunteer_count' => count($team_volunteers),
                        'total_hours' => round($total_team_hours, 1),
                        'volunteers' => $team_volunteers
                    );
                }
            }
            
            // Sort teams by total hours descending
            usort($teams, function($a, $b) {
                return $b['total_hours'] <=> $a['total_hours'];
            });
            
            claws_log('Returning ' . count($teams) . ' teams with logged hours', 'info');
            
            return new WP_REST_Response(array('teams' => $teams), 200);
            
        } catch (Exception $e) {
            claws_log('Error getting team hours: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve team hours', array('status' => 500));
        }
    }
    
    /**
     * Helper: Count user participations in events or projects
     */
    private function count_user_participations($user_id, $type) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'type',
                    'value' => $type,
                    'compare' => '='
                )
            )
        );
        
        $opportunities = get_posts($args);
        $count = 0;
        
        foreach ($opportunities as $opp) {
            $spots = get_post_meta($opp->ID, 'volunteer_spots', true);
            if (!is_array($spots)) continue;
            
            foreach ($spots as $spot) {
                if (!empty($spot['volunteer_id']) && $spot['volunteer_id'] == $user_id) {
                    $count++;
                    break;
                }
            }
        }
        
        return $count;
    }
    
    /**
     * Helper: Count active opportunities (events or projects)
     */
    private function count_active_opportunities($type) {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'type',
                    'value' => $type,
                    'compare' => '='
                ),
                array(
                    'key' => 'status',
                    'value' => array('upcoming', 'active'),
                    'compare' => 'IN'
                )
            )
        );
        
        return count(get_posts($args));
    }
    
    /**
     * Helper: Count active teams
     */
    private function count_active_teams() {
        $args = array(
            'post_type' => 'claws_event',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'status',
                    'value' => array('upcoming', 'active'),
                    'compare' => 'IN'
                )
            )
        );
        
        $all_opportunities = get_posts($args);
        $active_teams = 0;
        
        foreach ($all_opportunities as $opp) {
            // A team is active if it has a lead (lead_id is set)
            $lead_id = get_post_meta($opp->ID, 'lead_id', true);
            if (!empty($lead_id)) {
                $active_teams++;
            }
        }
        
        return $active_teams;
    }
    
    /**
     * Save volunteer time entry
     */
    public function save_volunteer_time($request) {
        try {
            claws_log('=== SAVE VOLUNTEER TIME STARTED ===', 'info');
            
            $params = $request->get_json_params();
            $volunteer_id = get_current_user_id();
            
            claws_log('Request params: ' . json_encode($params), 'info');
            claws_log('Current user ID (volunteer): ' . $volunteer_id, 'info');
            
            $post_data = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'post_title' => 'Volunteer Time - ' . date('Y-m-d H:i:s'),
                'post_author' => $volunteer_id
            );
            
            claws_log('Creating post with data: ' . json_encode($post_data), 'info');
            
            $time_id = wp_insert_post($post_data);
            
            if (is_wp_error($time_id)) {
                claws_log('ERROR: Failed to create post - ' . $time_id->get_error_message(), 'error');
                return new WP_Error('create_failed', 'Could not create time entry', array('status' => 500));
            }
            
            claws_log('✅ Post created successfully, ID: ' . $time_id, 'info');
            
            // Save metadata
            update_post_meta($time_id, 'volunteer_id', $volunteer_id);
            update_post_meta($time_id, 'date', sanitize_text_field($params['date']));
            update_post_meta($time_id, 'task_type', sanitize_text_field($params['task_type']));
            update_post_meta($time_id, 'colony_id', intval($params['colony_id']));
            update_post_meta($time_id, 'description', sanitize_textarea_field($params['description']));
            update_post_meta($time_id, 'start_time', sanitize_text_field($params['start_time']));
            update_post_meta($time_id, 'end_time', sanitize_text_field($params['end_time']));
            update_post_meta($time_id, 'hours', floatval($params['hours']));
            update_post_meta($time_id, 'coordinator_id', intval($params['coordinator_id']));
            update_post_meta($time_id, 'approval_status', 'pending');
            update_post_meta($time_id, 'submitted_at', current_time('mysql'));
            // Event/Project linkage
            if (!empty($params['event_id'])) {
                update_post_meta($time_id, 'event_id', intval($params['event_id']));
            }
            if (!empty($params['project_id'])) {
                update_post_meta($time_id, 'project_id', intval($params['project_id']));
            }
            
            claws_log('✅ All metadata saved', 'info');
            claws_log('  - volunteer_id: ' . $volunteer_id, 'info');
            claws_log('  - coordinator_id: ' . intval($params['coordinator_id']), 'info');
            claws_log('  - approval_status: pending', 'info');
            claws_log('  - task_type: ' . sanitize_text_field($params['task_type']), 'info');
            claws_log('  - hours: ' . floatval($params['hours']), 'info');
            
            // Send email notification to coordinator
            $coordinator_id = intval($params['coordinator_id']);
            $coordinator = get_user_by('ID', $coordinator_id);
            $volunteer = wp_get_current_user();
            
            claws_log('Preparing to send email to coordinator', 'info');
            claws_log('  - Coordinator: ' . ($coordinator ? $coordinator->display_name : 'NOT FOUND'), 'info');
            claws_log('  - Coordinator email: ' . ($coordinator ? $coordinator->user_email : 'N/A'), 'info');
            claws_log('  - Volunteer: ' . $volunteer->display_name, 'info');
            
            if ($coordinator && $coordinator->user_email) {
                $subject = 'New Volunteer Task Pending Your Approval';
                $message = "Hello {$coordinator->display_name},\n\n";
                $message .= "{$volunteer->display_name} has submitted a completed task for your review:\n\n";
                $message .= "Task Type: " . sanitize_text_field($params['task_type']) . "\n";
                $message .= "Date: " . sanitize_text_field($params['date']) . "\n";
                $message .= "Hours: " . floatval($params['hours']) . "\n";
                $message .= "Description: " . sanitize_textarea_field($params['description']) . "\n\n";
                $message .= "Please log in to review and approve this task.\n\n";
                $message .= "---\n";
                $message .= "This is an automated message from " . get_bloginfo('name') . "\n";
                
                $email_sent = wp_mail($coordinator->user_email, $subject, $message);
                claws_log('Email sent status: ' . ($email_sent ? 'SUCCESS' : 'FAILED'), $email_sent ? 'info' : 'error');
            } else {
                claws_log('⚠️ WARNING: No coordinator found or no email address', 'warning');
            }
            
            claws_log('=== SAVE VOLUNTEER TIME COMPLETED SUCCESSFULLY ===', 'info');
            claws_log('Returning response with ID: ' . $time_id, 'info');
            
            return new WP_REST_Response(array(
                'success' => true,
                'id' => $time_id
            ), 200);
            
        } catch (Exception $e) {
            claws_log('❌ EXCEPTION in save_volunteer_time: ' . $e->getMessage(), 'error');
            claws_log('Stack trace: ' . $e->getTraceAsString(), 'error');
            return new WP_Error('save_failed', 'Could not save time entry', array('status' => 500));
        }
    }
    
    /**
     * Get a single volunteer time entry (for editing)
     */
    public function get_volunteer_time($request) {
        $time_id = intval($request->get_param('id'));
        $current_user_id = get_current_user_id();
        
        // Verify this user created this entry (or is an admin)
        $volunteer_id = intval(get_post_meta($time_id, 'volunteer_id', true));
        
        if ($volunteer_id !== $current_user_id && !current_user_can('manage_options')) {
            return new WP_Error('unauthorized', 'You are not authorized to view this entry', array('status' => 403));
        }
        
        // Get all the task data
        $task = array(
            'id' => $time_id,
            'date' => get_post_meta($time_id, 'date', true),
            'task_type' => get_post_meta($time_id, 'task_type', true),
            'colony_id' => get_post_meta($time_id, 'colony_id', true),
            'description' => get_post_meta($time_id, 'description', true),
            'start_time' => get_post_meta($time_id, 'start_time', true),
            'end_time' => get_post_meta($time_id, 'end_time', true),
            'hours' => floatval(get_post_meta($time_id, 'hours', true)),
            'coordinator_id' => intval(get_post_meta($time_id, 'coordinator_id', true)),
            'approval_status' => get_post_meta($time_id, 'approval_status', true),
            'volunteer_id' => $volunteer_id
        );
        
        return new WP_REST_Response($task, 200);
    }
    
    /**
     * Update a volunteer time entry
     */
    public function update_volunteer_time($request) {
        $time_id = intval($request->get_param('id'));
        $current_user_id = get_current_user_id();
        $params = $request->get_json_params();
        
        claws_log('=== UPDATE VOLUNTEER TIME STARTED ===', 'info');
        claws_log('Task ID: ' . $time_id, 'info');
        claws_log('Update params: ' . json_encode($params), 'info');
        
        // Verify this user created this entry (or is an admin)
        $volunteer_id = intval(get_post_meta($time_id, 'volunteer_id', true));
        
        if ($volunteer_id !== $current_user_id && !current_user_can('manage_options')) {
            return new WP_Error('unauthorized', 'You are not authorized to update this entry', array('status' => 403));
        }
        
        // Only allow updating pending or rejected tasks
        $old_status = get_post_meta($time_id, 'approval_status', true);
        if ($old_status === 'approved') {
            return new WP_Error('cannot_update', 'Cannot update approved tasks', array('status' => 400));
        }
        
        // Update metadata
        update_post_meta($time_id, 'date', sanitize_text_field($params['date']));
        update_post_meta($time_id, 'task_type', sanitize_text_field($params['task_type']));
        update_post_meta($time_id, 'colony_id', intval($params['colony_id']));
        update_post_meta($time_id, 'description', sanitize_textarea_field($params['description']));
        update_post_meta($time_id, 'start_time', sanitize_text_field($params['start_time']));
        update_post_meta($time_id, 'end_time', sanitize_text_field($params['end_time']));
        update_post_meta($time_id, 'hours', floatval($params['hours']));
        update_post_meta($time_id, 'coordinator_id', intval($params['coordinator_id']));
        
        // Event/Project linkage
        if (!empty($params['event_id'])) {
            update_post_meta($time_id, 'event_id', intval($params['event_id']));
        } else {
            delete_post_meta($time_id, 'event_id');
        }
        if (!empty($params['project_id'])) {
            update_post_meta($time_id, 'project_id', intval($params['project_id']));
        } else {
            delete_post_meta($time_id, 'project_id');
        }
        
        // CRITICAL: Reset to pending status (clears rejection)
        update_post_meta($time_id, 'approval_status', 'pending');
        
        // Clear rejection data
        delete_post_meta($time_id, 'rejection_reason');
        delete_post_meta($time_id, 'rejected_by');
        delete_post_meta($time_id, 'rejected_at');
        
        // Update submission timestamp
        update_post_meta($time_id, 'submitted_at', current_time('mysql'));
        
        claws_log('✅ Task updated successfully', 'info');
        claws_log('  - Old status: ' . $old_status, 'info');
        claws_log('  - New status: pending', 'info');
        
        // If task was rejected and is now resubmitted, send email to coordinator
        if ($old_status === 'rejected') {
            $coordinator_id = intval($params['coordinator_id']);
            $coordinator = get_user_by('ID', $coordinator_id);
            $volunteer = wp_get_current_user();
            
            if ($coordinator && $coordinator->user_email) {
                $subject = 'Volunteer Task Re-Submitted for Approval';
                $message = "Hello {$coordinator->display_name},\n\n";
                $message .= "{$volunteer->display_name} has updated and re-submitted a task for your review:\n\n";
                $message .= "Task Type: " . sanitize_text_field($params['task_type']) . "\n";
                $message .= "Date: " . sanitize_text_field($params['date']) . "\n";
                $message .= "Hours: " . floatval($params['hours']) . "\n";
                $message .= "Description: " . sanitize_textarea_field($params['description']) . "\n\n";
                $message .= "Please log in to review and approve this task.\n\n";
                $message .= "---\n";
                $message .= "This is an automated message from " . get_bloginfo('name') . "\n";
                
                wp_mail($coordinator->user_email, $subject, $message);
                claws_log('✅ Re-submission email sent to coordinator', 'info');
            }
        }
        
        claws_log('=== UPDATE VOLUNTEER TIME COMPLETED ===', 'info');
        
        return new WP_REST_Response(array(
            'success' => true,
            'id' => $time_id
        ), 200);
    }
    
    /**
     * Get pending volunteer time entries
     * Volunteers see their own pending tasks
     * Admins/Coordinators see tasks based on 'view' parameter:
     *   - view=my: Show their own submitted tasks (like volunteers)
     *   - view=approve: Show tasks assigned to them for approval
     */
    public function get_pending_volunteer_time($request) {
        claws_log('=== GET PENDING VOLUNTEER TIME STARTED ===', 'info');
        
        $current_user_id = get_current_user_id();
        $is_admin = current_user_can('manage_options') || current_user_can('edit_others_posts');
        $view = $request->get_param('view'); // 'my' or 'approve'
        
        claws_log('Current user ID: ' . $current_user_id, 'info');
        claws_log('Is admin: ' . ($is_admin ? 'YES' : 'NO'), 'info');
        claws_log('View parameter: ' . ($view ?: 'not set'), 'info');
        
        // Determine which tasks to show
        if ($is_admin && $view === 'approve') {
            claws_log('📋 Mode: ADMIN viewing tasks needing approval', 'info');
            // Admin viewing tasks that need their approval
            $args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'coordinator_id',
                        'value' => $current_user_id,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'approval_status',
                        'value' => 'pending',
                        'compare' => '='
                    )
                ),
                'orderby' => 'date',
                'order' => 'DESC'
            );
            claws_log('Query: Tasks where coordinator_id=' . $current_user_id . ' AND status=pending', 'info');
        } else {
            claws_log('📋 Mode: VOLUNTEER/USER viewing their own tasks', 'info');
            // Everyone else (volunteers, or admins viewing their own tasks)
            // Include both pending AND rejected tasks
            $args = array(
                'post_type' => 'claws_volunteer_time',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'volunteer_id',
                        'value' => $current_user_id,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'approval_status',
                        'value' => array('pending', 'rejected'),
                        'compare' => 'IN'
                    )
                ),
                'orderby' => 'date',
                'order' => 'DESC'
            );
            claws_log('Query: Tasks where volunteer_id=' . $current_user_id . ' AND status IN (pending, rejected)', 'info');
        }
        
        claws_log('Executing query...', 'info');
        $posts = get_posts($args);
        claws_log('Query returned ' . count($posts) . ' posts', 'info');
        
        $entries = array();
        
        foreach ($posts as $post) {
            $volunteer_id = get_post_meta($post->ID, 'volunteer_id', true);
            $coordinator_id = get_post_meta($post->ID, 'coordinator_id', true);
            $status = get_post_meta($post->ID, 'approval_status', true);
            $volunteer = get_user_by('ID', $volunteer_id);
            
            claws_log('  Post #' . $post->ID . ': volunteer=' . $volunteer_id . ', coordinator=' . $coordinator_id . ', status=' . $status, 'info');
            
            $entries[] = array(
                'id' => $post->ID,
                'date' => get_post_meta($post->ID, 'date', true),
                'task_type' => get_post_meta($post->ID, 'task_type', true),
                'description' => get_post_meta($post->ID, 'description', true),
                'hours' => floatval(get_post_meta($post->ID, 'hours', true)),
                'volunteer_id' => $volunteer_id,
                'volunteer_name' => $volunteer ? $volunteer->display_name : 'Unknown',
                'approval_status' => $status,
                'rejection_reason' => get_post_meta($post->ID, 'rejection_reason', true),
                'submitted_at' => get_post_meta($post->ID, 'submitted_at', true)
            );
        }
        
        claws_log('Returning ' . count($entries) . ' entries', 'info');
        claws_log('=== GET PENDING VOLUNTEER TIME COMPLETED ===', 'info');
        
        return new WP_REST_Response($entries, 200);
    }
    
    /**
     * Get approved volunteer time entries for current user
     */
    public function get_approved_volunteer_time($request) {
        $volunteer_id = get_current_user_id();
        $months = intval($request->get_param('months')) ?: 3;
        
        $date_limit = date('Y-m-d', strtotime("-{$months} months"));
        
        $args = array(
            'post_type' => 'claws_volunteer_time',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'volunteer_id',
                    'value' => $volunteer_id,
                    'compare' => '='
                ),
                array(
                    'key' => 'approval_status',
                    'value' => 'approved',
                    'compare' => '='
                ),
                array(
                    'key' => 'date',
                    'value' => $date_limit,
                    'compare' => '>=',
                    'type' => 'DATE'
                )
            ),
            'orderby' => 'date',
            'order' => 'DESC'
        );
        
        $posts = get_posts($args);
        $entries = array();
        
        foreach ($posts as $post) {
            $entries[] = array(
                'id' => $post->ID,
                'date' => get_post_meta($post->ID, 'date', true),
                'task_type' => get_post_meta($post->ID, 'task_type', true),
                'description' => get_post_meta($post->ID, 'description', true),
                'hours' => floatval(get_post_meta($post->ID, 'hours', true)),
                'approved_at' => get_post_meta($post->ID, 'approved_at', true)
            );
        }
        
        return new WP_REST_Response($entries, 200);
    }
    
    /**
     * Approve volunteer time entry (coordinators only)
     */
    public function approve_volunteer_time($request) {
        $time_id = intval($request->get_param('id'));
        $coordinator_id = get_current_user_id();
        
        // Verify this user is the coordinator for this entry
        $entry_coordinator_id = intval(get_post_meta($time_id, 'coordinator_id', true));
        
        if ($entry_coordinator_id !== $coordinator_id && !current_user_can('manage_options')) {
            return new WP_Error('unauthorized', 'You are not authorized to approve this entry', array('status' => 403));
        }
        
        // Update status
        update_post_meta($time_id, 'approval_status', 'approved');
        update_post_meta($time_id, 'approved_by', $coordinator_id);
        update_post_meta($time_id, 'approved_at', current_time('mysql'));
        
        // Send confirmation email to volunteer
        $volunteer_id = intval(get_post_meta($time_id, 'volunteer_id', true));
        $volunteer = get_user_by('ID', $volunteer_id);
        $coordinator = wp_get_current_user();
        
        if ($volunteer && $volunteer->user_email) {
            $subject = 'Your Volunteer Task Has Been Approved';
            $message = "Hello {$volunteer->display_name},\n\n";
            $message .= "Good news! {$coordinator->display_name} has approved your completed task:\n\n";
            $message .= "Task Type: " . get_post_meta($time_id, 'task_type', true) . "\n";
            $message .= "Date: " . get_post_meta($time_id, 'date', true) . "\n";
            $message .= "Hours: " . get_post_meta($time_id, 'hours', true) . "\n\n";
            $message .= "Thank you for your volunteer work!\n\n";
            $message .= "---\n";
            $message .= "This is an automated message from " . get_bloginfo('name') . "\n";
            
            wp_mail($volunteer->user_email, $subject, $message);
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Time entry approved'
        ), 200);
    }
    
    /**
     * Reject a volunteer time entry
     */
    public function reject_volunteer_time($request) {
        $time_id = intval($request->get_param('id'));
        $coordinator_id = get_current_user_id();
        $params = $request->get_json_params();
        $reason = sanitize_textarea_field($params['reason'] ?? '');
        
        // Verify this user is the coordinator for this entry
        $entry_coordinator_id = intval(get_post_meta($time_id, 'coordinator_id', true));
        
        if ($entry_coordinator_id !== $coordinator_id && !current_user_can('manage_options')) {
            return new WP_Error('unauthorized', 'You are not authorized to reject this entry', array('status' => 403));
        }
        
        // Update status to rejected
        update_post_meta($time_id, 'approval_status', 'rejected');
        update_post_meta($time_id, 'rejected_by', $coordinator_id);
        update_post_meta($time_id, 'rejected_at', current_time('mysql'));
        update_post_meta($time_id, 'rejection_reason', $reason);
        
        // Send notification email to volunteer
        $volunteer_id = intval(get_post_meta($time_id, 'volunteer_id', true));
        $volunteer = get_user_by('ID', $volunteer_id);
        $coordinator = wp_get_current_user();
        
        if ($volunteer && $volunteer->user_email) {
            $subject = 'Volunteer Task Not Approved';
            $message = "Hello {$volunteer->display_name},\n\n";
            $message .= "{$coordinator->display_name} was unable to approve your submitted task:\n\n";
            $message .= "Task Type: " . get_post_meta($time_id, 'task_type', true) . "\n";
            $message .= "Date: " . get_post_meta($time_id, 'date', true) . "\n";
            $message .= "Hours: " . get_post_meta($time_id, 'hours', true) . "\n\n";
            
            if ($reason) {
                $message .= "Reason: {$reason}\n\n";
            }
            
            $message .= "If you have questions, please contact your coordinator.\n\n";
            $message .= "---\n";
            $message .= "This is an automated message from " . get_bloginfo('name') . "\n";
            
            wp_mail($volunteer->user_email, $subject, $message);
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Time entry rejected'
        ), 200);
    }
    
    /**
     * Delete a volunteer time entry
     */
    public function delete_volunteer_time($request) {
        $time_id = intval($request->get_param('id'));
        $current_user_id = get_current_user_id();
        
        // Verify this user created this entry (or is an admin)
        $volunteer_id = intval(get_post_meta($time_id, 'volunteer_id', true));
        
        if ($volunteer_id !== $current_user_id && !current_user_can('manage_options')) {
            return new WP_Error('unauthorized', 'You are not authorized to delete this entry', array('status' => 403));
        }
        
        // Only allow deleting pending or rejected tasks, not approved ones
        $status = get_post_meta($time_id, 'approval_status', true);
        if ($status === 'approved') {
            return new WP_Error('cannot_delete', 'Cannot delete approved tasks', array('status' => 400));
        }
        
        // Delete the post
        $result = wp_delete_post($time_id, true);
        
        if (!$result) {
            return new WP_Error('delete_failed', 'Failed to delete task', array('status' => 500));
        }
        
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Task deleted successfully'
        ), 200);
    }
    
    /**
     * Send a chat message (stores in database)
     */
    public function send_chat_message($request) {
        try {
            $params = $request->get_json_params();
            $chat_type = $params['chat_type'] ?? '';
            $chat_id = intval($params['chat_id'] ?? 0);
            $message = sanitize_textarea_field($params['message'] ?? '');
            
            if (empty($message)) {
                return new WP_Error('invalid_message', 'Message cannot be empty', array('status' => 400));
            }
            
            $sender = wp_get_current_user();
            $sender_id = $sender->ID;
            $sender_name = $sender->display_name;
            
            // For individual chats, store both user IDs for bidirectional lookup
            $recipient_id = null;
            if ($chat_type === 'individual') {
                $recipient_id = $chat_id;
            }
            
            // Create message post
            $post_data = array(
                'post_type' => 'claws_message',
                'post_status' => 'publish',
                'post_title' => 'Message from ' . $sender_name,
                'post_content' => $message,
                'post_author' => $sender_id
            );
            
            $message_id = wp_insert_post($post_data);
            
            if (is_wp_error($message_id)) {
                return new WP_Error('create_failed', 'Could not create message', array('status' => 500));
            }
            
            // Store metadata
            update_post_meta($message_id, 'chat_type', $chat_type);
            update_post_meta($message_id, 'chat_id', $chat_id);
            update_post_meta($message_id, 'sender_id', $sender_id);
            update_post_meta($message_id, 'sender_name', $sender_name);
            update_post_meta($message_id, 'timestamp', current_time('mysql'));
            
            // For individual chats, also store recipient_id for easier querying
            if ($recipient_id) {
                update_post_meta($message_id, 'recipient_id', $recipient_id);
                update_post_meta($message_id, 'is_read', '0'); // Mark as unread
            }
            
            claws_log("Message sent - Type: $chat_type, Chat ID: $chat_id, Sender: $sender_id, Recipient: $recipient_id", 'info');
            
            return new WP_REST_Response(array(
                'success' => true,
                'message_id' => $message_id
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error sending chat message: ' . $e->getMessage(), 'error');
            return new WP_Error('send_failed', 'Could not send message', array('status' => 500));
        }
    }
    
    /**
     * Get chat messages for a conversation
     */
    public function get_chat_messages($request) {
        try {
            $chat_type = $request->get_param('type');
            $chat_id = intval($request->get_param('id'));
            $current_user_id = get_current_user_id();
            
            // For individual chats, get messages where current user is EITHER sender OR recipient
            if ($chat_type === 'individual') {
                $args = array(
                    'post_type' => 'claws_message',
                    'post_status' => 'publish',
                    'posts_per_page' => 100,
                    'orderby' => 'date',
                    'order' => 'ASC',
                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' => 'chat_type',
                            'value' => 'individual',
                            'compare' => '='
                        ),
                        array(
                            'relation' => 'OR',
                            // Messages I sent to them
                            array(
                                'relation' => 'AND',
                                array(
                                    'key' => 'sender_id',
                                    'value' => $current_user_id,
                                    'compare' => '='
                                ),
                                array(
                                    'key' => 'recipient_id',
                                    'value' => $chat_id,
                                    'compare' => '='
                                )
                            ),
                            // Messages they sent to me
                            array(
                                'relation' => 'AND',
                                array(
                                    'key' => 'sender_id',
                                    'value' => $chat_id,
                                    'compare' => '='
                                ),
                                array(
                                    'key' => 'recipient_id',
                                    'value' => $current_user_id,
                                    'compare' => '='
                                )
                            )
                        )
                    )
                );
            } else {
                // Team chats - get all messages for this team
                $args = array(
                    'post_type' => 'claws_message',
                    'post_status' => 'publish',
                    'posts_per_page' => 100,
                    'orderby' => 'date',
                    'order' => 'ASC',
                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' => 'chat_type',
                            'value' => $chat_type,
                            'compare' => '='
                        ),
                        array(
                            'key' => 'chat_id',
                            'value' => $chat_id,
                            'compare' => '='
                        )
                    )
                );
            }
            
            $message_posts = get_posts($args);
            $messages = array();
            
            foreach ($message_posts as $post) {
                $messages[] = array(
                    'id' => $post->ID,
                    'message' => $post->post_content,
                    'sender_id' => get_post_meta($post->ID, 'sender_id', true),
                    'sender_name' => get_post_meta($post->ID, 'sender_name', true),
                    'time' => human_time_diff(strtotime($post->post_date), current_time('timestamp')) . ' ago',
                    'timestamp' => $post->post_date,
                    'is_read' => get_post_meta($post->ID, 'is_read', true)
                );
                
                // Mark as read if it's for me and I'm viewing it
                if ($chat_type === 'individual') {
                    $sender_id = get_post_meta($post->ID, 'sender_id', true);
                    if ($sender_id != $current_user_id) {
                        update_post_meta($post->ID, 'is_read', '1');
                    }
                }
            }
            
            claws_log("Retrieved " . count($messages) . " messages for $chat_type chat ID $chat_id (User: $current_user_id)", 'info');
            
            return new WP_REST_Response($messages, 200);
            
        } catch (Exception $e) {
            claws_log('Error getting chat messages: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not retrieve messages', array('status' => 500));
        }
    }
    
    /**
     * Check for new notifications (colonies, events, messages, stats)
     */
    public function check_notifications($request) {
        try {
            $user_id = get_current_user_id();
            $last_check = get_user_meta($user_id, 'claws_last_notification_check', true);
            
            // If no last check, set to 5 minutes ago
            if (!$last_check) {
                $last_check = strtotime('-5 minutes');
            }
            
            $last_check_date = date('Y-m-d H:i:s', $last_check);
            $notifications = array();
            
            // 1. Check for new colonies (if user can view colonies)
            $new_colonies = get_posts(array(
                'post_type' => 'claws_colony',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'date_query' => array(
                    array(
                        'after' => $last_check_date,
                        'inclusive' => false
                    )
                )
            ));
            
            if (count($new_colonies) > 0) {
                $notifications[] = array(
                    'type' => 'colony',
                    'count' => count($new_colonies),
                    'message' => count($new_colonies) . ' new ' . (count($new_colonies) === 1 ? 'colony' : 'colonies')
                );
            }
            
            // 2. Check for new events/projects with open spots
            $new_opportunities = get_posts(array(
                'post_type' => 'claws_event',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'date_query' => array(
                    array(
                        'after' => $last_check_date,
                        'inclusive' => false
                    )
                ),
                'meta_query' => array(
                    array(
                        'key' => 'status',
                        'value' => array('upcoming', 'active'),
                        'compare' => 'IN'
                    )
                )
            ));
            
            $opportunities_with_spots = 0;
            foreach ($new_opportunities as $opp) {
                $volunteer_spots = get_post_meta($opp->ID, 'volunteer_spots', true);
                if (is_array($volunteer_spots)) {
                    $open_spots = array_filter($volunteer_spots, function($spot) {
                        return empty($spot['volunteer_id']);
                    });
                    if (count($open_spots) > 0) {
                        $opportunities_with_spots++;
                    }
                }
            }
            
            if ($opportunities_with_spots > 0) {
                $notifications[] = array(
                    'type' => 'opportunity',
                    'count' => $opportunities_with_spots,
                    'message' => $opportunities_with_spots . ' new volunteer ' . ($opportunities_with_spots === 1 ? 'opportunity' : 'opportunities')
                );
            }
            
            // 3. Check for new messages (any chat user is part of)
            $new_messages = get_posts(array(
                'post_type' => 'claws_message',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'date_query' => array(
                    array(
                        'after' => $last_check_date,
                        'inclusive' => false
                    )
                ),
                'meta_query' => array(
                    array(
                        'key' => 'sender_id',
                        'value' => $user_id,
                        'compare' => '!='
                    )
                )
            ));
            
            if (count($new_messages) > 0) {
                $notifications[] = array(
                    'type' => 'message',
                    'count' => count($new_messages),
                    'message' => count($new_messages) . ' new ' . (count($new_messages) === 1 ? 'message' : 'messages')
                );
            }
            
            // 4. Check for new intakes/discharges (admins only)
            if (current_user_can('manage_options')) {
                $new_intakes = get_posts(array(
                    'post_type' => 'claws_intake',
                    'post_status' => 'publish',
                    'posts_per_page' => -1,
                    'date_query' => array(
                        array(
                            'after' => $last_check_date,
                            'inclusive' => false
                        )
                    )
                ));
                
                if (count($new_intakes) > 0) {
                    $notifications[] = array(
                        'type' => 'intake',
                        'count' => count($new_intakes),
                        'message' => count($new_intakes) . ' new ' . (count($new_intakes) === 1 ? 'intake' : 'intakes')
                    );
                }
            }
            
            // Update last check time
            update_user_meta($user_id, 'claws_last_notification_check', time());
            
            return new WP_REST_Response(array(
                'has_notifications' => count($notifications) > 0,
                'notifications' => $notifications,
                'total_count' => array_sum(array_column($notifications, 'count'))
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error checking notifications: ' . $e->getMessage(), 'error');
            return new WP_Error('check_failed', 'Could not check notifications', array('status' => 500));
        }
    }
    
    /**
     * Get unread message counts for all conversations
     */
    public function get_unread_message_counts($request) {
        try {
            $current_user_id = get_current_user_id();
            $unread_counts = array();
            
            // Get all unread messages where current user is recipient
            $unread_messages = get_posts(array(
                'post_type' => 'claws_message',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'recipient_id',
                        'value' => $current_user_id,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'is_read',
                        'value' => '0',
                        'compare' => '='
                    )
                )
            ));
            
            // Count by sender for individuals
            $individual_counts = array();
            foreach ($unread_messages as $msg) {
                $sender_id = get_post_meta($msg->ID, 'sender_id', true);
                $chat_type = get_post_meta($msg->ID, 'chat_type', true);
                
                if ($chat_type === 'individual') {
                    if (!isset($individual_counts[$sender_id])) {
                        $individual_counts[$sender_id] = 0;
                    }
                    $individual_counts[$sender_id]++;
                }
            }
            
            // Get unread team messages
            $team_messages = get_posts(array(
                'post_type' => 'claws_message',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    'relation' => 'AND',
                    array(
                        'key' => 'chat_type',
                        'value' => 'team',
                        'compare' => '='
                    ),
                    array(
                        'key' => 'sender_id',
                        'value' => $current_user_id,
                        'compare' => '!='
                    )
                ),
                'date_query' => array(
                    array(
                        'after' => '24 hours ago'
                    )
                )
            ));
            
            $team_counts = array();
            foreach ($team_messages as $msg) {
                $chat_id = get_post_meta($msg->ID, 'chat_id', true);
                if (!isset($team_counts[$chat_id])) {
                    $team_counts[$chat_id] = 0;
                }
                $team_counts[$chat_id]++;
            }
            
            return new WP_REST_Response(array(
                'individuals' => $individual_counts,
                'teams' => $team_counts,
                'total' => count($unread_messages) + count($team_messages)
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error getting unread counts: ' . $e->getMessage(), 'error');
            return new WP_Error('fetch_failed', 'Could not get unread counts', array('status' => 500));
        }
    }
    
    /**
     * Clear/delete a conversation
     */
    public function clear_conversation($request) {
        try {
            $chat_type = $request->get_param('type');
            $chat_id = intval($request->get_param('id'));
            $current_user_id = get_current_user_id();
            
            claws_log("Clearing $chat_type conversation $chat_id for user $current_user_id", 'info');
            
            // For individual chats, delete messages between current user and other user
            if ($chat_type === 'individual') {
                $messages = get_posts(array(
                    'post_type' => 'claws_message',
                    'post_status' => 'publish',
                    'posts_per_page' => -1,
                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' => 'chat_type',
                            'value' => 'individual',
                            'compare' => '='
                        ),
                        array(
                            'relation' => 'OR',
                            array(
                                'relation' => 'AND',
                                array('key' => 'sender_id', 'value' => $current_user_id, 'compare' => '='),
                                array('key' => 'recipient_id', 'value' => $chat_id, 'compare' => '=')
                            ),
                            array(
                                'relation' => 'AND',
                                array('key' => 'sender_id', 'value' => $chat_id, 'compare' => '='),
                                array('key' => 'recipient_id', 'value' => $current_user_id, 'compare' => '=')
                            )
                        )
                    )
                ));
            } else {
                // For team chats, only admins can clear (or implement per-user clearing)
                if (!current_user_can('manage_options')) {
                    return new WP_Error('unauthorized', 'Only admins can clear team conversations', array('status' => 403));
                }
                
                $messages = get_posts(array(
                    'post_type' => 'claws_message',
                    'post_status' => 'publish',
                    'posts_per_page' => -1,
                    'meta_query' => array(
                        'relation' => 'AND',
                        array('key' => 'chat_type', 'value' => $chat_type, 'compare' => '='),
                        array('key' => 'chat_id', 'value' => $chat_id, 'compare' => '=')
                    )
                ));
            }
            
            $deleted_count = 0;
            foreach ($messages as $message) {
                if (wp_delete_post($message->ID, true)) {
                    $deleted_count++;
                }
            }
            
            claws_log("Deleted $deleted_count messages from conversation", 'info');
            
            return new WP_REST_Response(array(
                'success' => true,
                'deleted_count' => $deleted_count
            ), 200);
            
        } catch (Exception $e) {
            claws_log('Error clearing conversation: ' . $e->getMessage(), 'error');
            return new WP_Error('delete_failed', 'Could not clear conversation', array('status' => 500));
        }
    }
    
    // ==========================================
    // DONOR MANAGEMENT
    // ==========================================
    
    public function get_donors($request) {
        try {
            $donors = get_posts(array(
                'post_type' => 'claws_donor',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'orderby' => 'date',
                'order' => 'DESC'
            ));
            
            $result = array();
            foreach ($donors as $donor) {
                $do_not_contact = get_post_meta($donor->ID, 'do_not_contact', true);
                $result[] = array(
                    'id' => $donor->ID,
                    'donor_id' => get_post_meta($donor->ID, 'donor_id', true),
                    'name' => $donor->post_title,
                    'email' => get_post_meta($donor->ID, 'email', true),
                    'phone' => get_post_meta($donor->ID, 'phone', true),
                    'date' => get_post_meta($donor->ID, 'donation_date', true),
                    'amount' => get_post_meta($donor->ID, 'donation_amount', true),
                    'donation_type' => get_post_meta($donor->ID, 'donation_type', true),
                    'purpose' => get_post_meta($donor->ID, 'purpose', true),
                    'payment_method' => get_post_meta($donor->ID, 'payment_method', true),
                    'acknowledged' => get_post_meta($donor->ID, 'acknowledged', true) === 'yes',
                    'do_not_contact' => ($do_not_contact === '1' || $do_not_contact === 'true' || $do_not_contact === true)
                );
            }
            
            return new WP_REST_Response($result, 200);
        } catch (Exception $e) {
            return new WP_Error('fetch_failed', 'Could not retrieve donors', array('status' => 500));
        }
    }
    
    public function create_donor($request) {
        try {
            $params = $request->get_json_params();
            
            $post_id = wp_insert_post(array(
                'post_type' => 'claws_donor',
                'post_title' => sanitize_text_field($params['name']),
                'post_status' => 'publish'
            ));
            
            if (is_wp_error($post_id)) {
                return new WP_Error('create_failed', 'Could not create donor', array('status' => 500));
            }
            
            update_post_meta($post_id, 'donor_id', sanitize_text_field($params['donor_id']));
            update_post_meta($post_id, 'email', sanitize_email($params['email'] ?? ''));
            update_post_meta($post_id, 'phone', sanitize_text_field($params['phone'] ?? ''));
            update_post_meta($post_id, 'donation_date', sanitize_text_field($params['date']));
            update_post_meta($post_id, 'donation_amount', floatval($params['amount']));
            update_post_meta($post_id, 'donation_type', sanitize_text_field($params['donation_type']));
            update_post_meta($post_id, 'purpose', sanitize_textarea_field($params['purpose']));
            update_post_meta($post_id, 'payment_method', sanitize_text_field($params['payment_method']));
            update_post_meta($post_id, 'acknowledged', !empty($params['acknowledged']) ? 'yes' : 'no');

            // Respect "Do Not Contact" preference.
            // If the donor was created from an existing contact (matched by email), inherit the flag.
            $do_not_contact = (!empty($params['do_not_contact']) && in_array($params['do_not_contact'], array(true, 'true', '1', 1, 'yes', 'on'), true));
            $email = sanitize_email($params['email'] ?? '');
            if (!$do_not_contact && !empty($email)) {
                $contact_match = get_posts(array(
                    'post_type' => 'claws_contact',
                    'post_status' => 'publish',
                    'posts_per_page' => 1,
                    'meta_query' => array(
                        array(
                            'key' => 'email',
                            'value' => $email,
                            'compare' => '='
                        )
                    )
                ));
                if (!empty($contact_match)) {
                    $contact_flag = get_post_meta($contact_match[0]->ID, 'do_not_contact', true);
                    $do_not_contact = ($contact_flag === '1' || $contact_flag === 'true' || $contact_flag === true);
                }
            }
            update_post_meta($post_id, 'do_not_contact', $do_not_contact ? '1' : '0');
            
            return new WP_REST_Response(array('success' => true, 'id' => $post_id), 200);
        } catch (Exception $e) {
            return new WP_Error('create_failed', 'Could not create donor', array('status' => 500));
        }
    }
    
    public function update_donor($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            
            wp_update_post(array(
                'ID' => $id,
                'post_title' => sanitize_text_field($params['name'])
            ));
            
            update_post_meta($id, 'donor_id', sanitize_text_field($params['donor_id']));
            update_post_meta($id, 'email', sanitize_email($params['email'] ?? ''));
            update_post_meta($id, 'phone', sanitize_text_field($params['phone'] ?? ''));
            update_post_meta($id, 'donation_date', sanitize_text_field($params['date']));
            update_post_meta($id, 'donation_amount', floatval($params['amount']));
            update_post_meta($id, 'donation_type', sanitize_text_field($params['donation_type']));
            update_post_meta($id, 'purpose', sanitize_textarea_field($params['purpose']));
            update_post_meta($id, 'payment_method', sanitize_text_field($params['payment_method']));
            update_post_meta($id, 'acknowledged', $params['acknowledged'] ? 'yes' : 'no');

            $do_not_contact = (!empty($params['do_not_contact']) && in_array($params['do_not_contact'], array(true, 'true', '1', 1, 'yes', 'on'), true));
            $email = sanitize_email($params['email'] ?? '');
            if (!$do_not_contact && !empty($email)) {
                $contact_match = get_posts(array(
                    'post_type' => 'claws_contact',
                    'post_status' => 'publish',
                    'posts_per_page' => 1,
                    'meta_query' => array(
                        array(
                            'key' => 'email',
                            'value' => $email,
                            'compare' => '='
                        )
                    )
                ));
                if (!empty($contact_match)) {
                    $contact_flag = get_post_meta($contact_match[0]->ID, 'do_not_contact', true);
                    $do_not_contact = ($contact_flag === '1' || $contact_flag === 'true' || $contact_flag === true);
                }
            }
            update_post_meta($id, 'do_not_contact', $do_not_contact ? '1' : '0');
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('update_failed', 'Could not update donor', array('status' => 500));
        }
    }
    
    public function delete_donor($request) {
        try {
            $id = intval($request->get_param('id'));
            wp_delete_post($id, true);
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('delete_failed', 'Could not delete donor', array('status' => 500));
        }
    }
    
    // ==========================================
    // SPONSOR MANAGEMENT
    // ==========================================
    
    public function get_sponsors($request) {
        try {
            $sponsors = get_posts(array(
                'post_type' => 'claws_sponsor',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'orderby' => 'date',
                'order' => 'DESC'
            ));
            
            $result = array();
            foreach ($sponsors as $sponsor) {
                $result[] = array(
                    'id' => $sponsor->ID,
                    'name' => $sponsor->post_title,
                    'website' => get_post_meta($sponsor->ID, 'website', true),
                    'contact_name' => get_post_meta($sponsor->ID, 'contact_name', true),
                    'email' => get_post_meta($sponsor->ID, 'email', true),
                    'phone' => get_post_meta($sponsor->ID, 'phone', true),
                    'sponsorship_type' => get_post_meta($sponsor->ID, 'sponsorship_type', true),
                    'amount_asked' => get_post_meta($sponsor->ID, 'amount_asked', true),
                    'amount' => get_post_meta($sponsor->ID, 'amount', true),
                    'frequency' => get_post_meta($sponsor->ID, 'frequency', true),
                    'start_date' => get_post_meta($sponsor->ID, 'start_date', true),
                    'status' => get_post_meta($sponsor->ID, 'status', true),
                    'notes' => get_post_meta($sponsor->ID, 'notes', true)
                );
            }
            
            return new WP_REST_Response($result, 200);
        } catch (Exception $e) {
            return new WP_Error('fetch_failed', 'Could not retrieve sponsors', array('status' => 500));
        }
    }
    
    public function create_sponsor($request) {
        try {
            $params = $request->get_json_params();
            
            $post_id = wp_insert_post(array(
                'post_type' => 'claws_sponsor',
                'post_title' => sanitize_text_field($params['name']),
                'post_status' => 'publish'
            ));
            
            if (is_wp_error($post_id)) {
                return new WP_Error('create_failed', 'Could not create sponsor', array('status' => 500));
            }
            
            update_post_meta($post_id, 'website', esc_url_raw($params['website']));
            update_post_meta($post_id, 'contact_name', sanitize_text_field($params['contact_name']));
            update_post_meta($post_id, 'email', sanitize_email($params['email']));
            update_post_meta($post_id, 'phone', sanitize_text_field($params['phone']));
            update_post_meta($post_id, 'sponsorship_type', sanitize_text_field($params['sponsorship_type']));
            update_post_meta($post_id, 'amount_asked', floatval($params['amount_asked']));
            update_post_meta($post_id, 'amount', floatval($params['amount']));
            update_post_meta($post_id, 'frequency', sanitize_text_field($params['frequency']));
            update_post_meta($post_id, 'start_date', sanitize_text_field($params['start_date']));
            update_post_meta($post_id, 'status', sanitize_text_field($params['status']));
            update_post_meta($post_id, 'notes', sanitize_textarea_field($params['notes']));
            
            return new WP_REST_Response(array('success' => true, 'id' => $post_id), 200);
        } catch (Exception $e) {
            return new WP_Error('create_failed', 'Could not create sponsor', array('status' => 500));
        }
    }
    
    public function update_sponsor($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            
            wp_update_post(array(
                'ID' => $id,
                'post_title' => sanitize_text_field($params['name'])
            ));
            
            update_post_meta($id, 'website', esc_url_raw($params['website']));
            update_post_meta($id, 'contact_name', sanitize_text_field($params['contact_name']));
            update_post_meta($id, 'email', sanitize_email($params['email']));
            update_post_meta($id, 'phone', sanitize_text_field($params['phone']));
            update_post_meta($id, 'sponsorship_type', sanitize_text_field($params['sponsorship_type']));
            update_post_meta($id, 'amount_asked', floatval($params['amount_asked']));
            update_post_meta($id, 'amount', floatval($params['amount']));
            update_post_meta($id, 'frequency', sanitize_text_field($params['frequency']));
            update_post_meta($id, 'start_date', sanitize_text_field($params['start_date']));
            update_post_meta($id, 'status', sanitize_text_field($params['status']));
            update_post_meta($id, 'notes', sanitize_textarea_field($params['notes']));
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('update_failed', 'Could not update sponsor', array('status' => 500));
        }
    }
    
    public function delete_sponsor($request) {
        try {
            $id = intval($request->get_param('id'));
            wp_delete_post($id, true);
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('delete_failed', 'Could not delete sponsor', array('status' => 500));
        }
    }
    
    // ==========================================
    // VOLUNTEER APPLICATION MANAGEMENT
    // ==========================================
    
    public function get_volunteer_applications($request) {
        try {
            $status = $request->get_param('status') ?: 'pending';
            
            $applications = get_posts(array(
                'post_type' => 'claws_volunteer_app',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'status',
                        'value' => $status,
                        'compare' => '='
                    )
                ),
                'orderby' => 'date',
                'order' => 'DESC'
            ));
            
            $result = array();
            foreach ($applications as $app) {
                $result[] = array(
                    'id' => $app->ID,
                    'name' => $app->post_title,
                    'first_name' => get_post_meta($app->ID, 'first_name', true),
                    'last_name' => get_post_meta($app->ID, 'last_name', true),
                    'email' => get_post_meta($app->ID, 'email', true),
                    'phone' => get_post_meta($app->ID, 'phone', true),
                    'birthday' => get_post_meta($app->ID, 'birthday', true),
                    'volunteer_type' => get_post_meta($app->ID, 'volunteer_type', true),
                    'notes' => get_post_meta($app->ID, 'notes', true),
                    'username' => get_post_meta($app->ID, 'username', true),
                    'status' => get_post_meta($app->ID, 'status', true),
                    'submitted_date' => $app->post_date,
                    'denial_reason' => get_post_meta($app->ID, 'denial_reason', true),
                    'reviewed_by' => get_post_meta($app->ID, 'reviewed_by', true),
                    'reviewed_date' => get_post_meta($app->ID, 'reviewed_date', true)
                );
            }
            
            return new WP_REST_Response($result, 200);
        } catch (Exception $e) {
            return new WP_Error('fetch_failed', 'Could not retrieve applications', array('status' => 500));
        }
    }
    
    public function create_volunteer_application($request) {
        try {
            $params = $request->get_json_params();
            
            $full_name = trim($params['first_name'] . ' ' . $params['last_name']);
            
            $post_id = wp_insert_post(array(
                'post_type' => 'claws_volunteer_app',
                'post_title' => $full_name,
                'post_status' => 'publish'
            ));
            
            if (is_wp_error($post_id)) {
                return new WP_Error('create_failed', 'Could not create application', array('status' => 500));
            }
            
            update_post_meta($post_id, 'first_name', sanitize_text_field($params['first_name']));
            update_post_meta($post_id, 'last_name', sanitize_text_field($params['last_name']));
            update_post_meta($post_id, 'email', sanitize_email($params['email']));
            update_post_meta($post_id, 'phone', sanitize_text_field($params['phone']));
            update_post_meta($post_id, 'birthday', sanitize_text_field($params['birthday']));
            update_post_meta($post_id, 'volunteer_type', sanitize_text_field($params['volunteer_type']));
            update_post_meta($post_id, 'notes', sanitize_textarea_field($params['notes']));
            update_post_meta($post_id, 'username', sanitize_text_field($params['username']));
            update_post_meta($post_id, 'status', 'pending');
            
            return new WP_REST_Response(array('success' => true, 'id' => $post_id), 200);
        } catch (Exception $e) {
            return new WP_Error('create_failed', 'Could not create application', array('status' => 500));
        }
    }
    
    public function approve_volunteer_application($request) {
        try {
            $id = intval($request->get_param('id'));
            $current_user = wp_get_current_user();
            
            // Get applicant info
            $app = get_post($id);
            $email = get_post_meta($id, 'email', true);
            $name = $app->post_title;
            
            // Update application status
            update_post_meta($id, 'status', 'approved');
            update_post_meta($id, 'reviewed_by', $current_user->display_name);
            update_post_meta($id, 'reviewed_date', current_time('mysql'));
            
            // Send approval email
            $to = $email;
            $subject = 'Volunteer Application Approved - CLAWS';
            $message = "$name, we are happy to report that your application has been approved and you are now officially part of our agency family. Welcome aboard!";
            $headers = array('Content-Type: text/html; charset=UTF-8');
            
            wp_mail($to, $subject, $message, $headers);
            
            claws_log("Volunteer application #$id approved by {$current_user->display_name}");
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('approve_failed', 'Could not approve application', array('status' => 500));
        }
    }
    
    public function deny_volunteer_application($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            $reason = sanitize_textarea_field($params['reason']);
            
            if (empty($reason)) {
                return new WP_Error('missing_reason', 'Denial reason is required', array('status' => 400));
            }
            
            $current_user = wp_get_current_user();
            
            // Get applicant info
            $app = get_post($id);
            $email = get_post_meta($id, 'email', true);
            $name = $app->post_title;
            
            // Update application status
            update_post_meta($id, 'status', 'denied');
            update_post_meta($id, 'denial_reason', $reason);
            update_post_meta($id, 'reviewed_by', $current_user->display_name);
            update_post_meta($id, 'reviewed_date', current_time('mysql'));
            
            // Send denial email
            $to = $email;
            $subject = 'Volunteer Application Update - CLAWS';
            $message = "$name, unfortunately, we were unable to approve your volunteer application at this time. Please contact us at your earliest convenience to discuss.";
            $headers = array('Content-Type: text/html; charset=UTF-8');
            
            wp_mail($to, $subject, $message, $headers);
            
            claws_log("Volunteer application #$id denied by {$current_user->display_name}. Reason: $reason");
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('deny_failed', 'Could not deny application', array('status' => 500));
        }
    }
    
    // ==========================================
    // CONTACT MANAGEMENT
    // ==========================================
    
    public function get_contacts($request) {
        error_log('CLAWS: get_contacts called');
        error_log('CLAWS: User ID: ' . get_current_user_id());
        error_log('CLAWS: User roles: ' . print_r(wp_get_current_user()->roles, true));
        
        try {
            $status = $request->get_param('status') ?: 'active';
            error_log('CLAWS: Fetching contacts with status: ' . $status);
            
            $contacts = get_posts(array(
                'post_type' => 'claws_contact',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'status',
                        'value' => $status,
                        'compare' => '='
                    )
                ),
                'orderby' => 'date',
                'order' => 'DESC'
            ));
            
            error_log('CLAWS: Found ' . count($contacts) . ' contacts');
            
            $result = array();
            foreach ($contacts as $contact) {
                $do_not_contact = get_post_meta($contact->ID, 'do_not_contact', true);
                $result[] = array(
                    'id' => $contact->ID,
                    'first_name' => get_post_meta($contact->ID, 'first_name', true),
                    'last_name' => get_post_meta($contact->ID, 'last_name', true),
                    'name' => $contact->post_title,
                    'email' => get_post_meta($contact->ID, 'email', true),
                    'phone' => get_post_meta($contact->ID, 'phone', true),
                    'birthday' => get_post_meta($contact->ID, 'birthday', true),
                    'do_not_contact' => ($do_not_contact === '1' || $do_not_contact === 'true' || $do_not_contact === true),
                    'notes' => get_post_meta($contact->ID, 'notes', true),
                    'contact_type' => get_post_meta($contact->ID, 'contact_type', true),
                    'username' => get_post_meta($contact->ID, 'username', true),
                    'status' => get_post_meta($contact->ID, 'status', true),
                    'created_date' => $contact->post_date,
                    'deleted_by' => get_post_meta($contact->ID, 'deleted_by', true),
                    'deleted_date' => get_post_meta($contact->ID, 'deleted_date', true),
                    'deletion_notes' => get_post_meta($contact->ID, 'deletion_notes', true)
                );
            }
            
            error_log('CLAWS: Returning ' . count($result) . ' contact records');
            return new WP_REST_Response($result, 200);
        } catch (Exception $e) {
            error_log('CLAWS ERROR in get_contacts: ' . $e->getMessage());
            error_log('CLAWS ERROR trace: ' . $e->getTraceAsString());
            return new WP_Error('fetch_failed', 'Could not retrieve contacts: ' . $e->getMessage(), array('status' => 500));
        }
    }
    
    public function create_contact($request) {
        error_log('CLAWS: create_contact called');
        error_log('CLAWS: User ID: ' . get_current_user_id());
        
        try {
            $params = $request->get_json_params();
            error_log('CLAWS: Contact params: ' . print_r($params, true));
            
            // Validate: must have either email or phone
            if (empty($params['email']) && empty($params['phone'])) {
                error_log('CLAWS ERROR: Validation failed - no email or phone');
                return new WP_Error('validation_error', 'Either email or phone is required', array('status' => 400));
            }
            
            $full_name = trim($params['first_name'] . ' ' . $params['last_name']);
            error_log('CLAWS: Creating contact: ' . $full_name);
            
            $post_id = wp_insert_post(array(
                'post_type' => 'claws_contact',
                'post_title' => $full_name,
                'post_status' => 'publish'
            ));
            
            if (is_wp_error($post_id)) {
                error_log('CLAWS ERROR: wp_insert_post failed: ' . $post_id->get_error_message());
                return new WP_Error('create_failed', 'Could not create contact: ' . $post_id->get_error_message(), array('status' => 500));
            }
            
            error_log('CLAWS: Contact post created with ID: ' . $post_id);
            
            update_post_meta($post_id, 'first_name', sanitize_text_field($params['first_name']));
            update_post_meta($post_id, 'last_name', sanitize_text_field($params['last_name']));
            update_post_meta($post_id, 'email', sanitize_email($params['email']));
            update_post_meta($post_id, 'phone', sanitize_text_field($params['phone']));
            update_post_meta($post_id, 'birthday', sanitize_text_field($params['birthday']));
            $do_not_contact = (!empty($params['do_not_contact']) && in_array($params['do_not_contact'], array(true, 'true', '1', 1, 'yes', 'on'), true));
            update_post_meta($post_id, 'do_not_contact', $do_not_contact ? '1' : '0');
            update_post_meta($post_id, 'notes', sanitize_textarea_field($params['notes']));
            update_post_meta($post_id, 'contact_type', sanitize_text_field($params['contact_type']));
            update_post_meta($post_id, 'username', sanitize_text_field($params['username']));
            update_post_meta($post_id, 'status', 'active');
            
            claws_log("Contact created: $full_name (ID: $post_id)");
            error_log('CLAWS: Contact created successfully');
            
            return new WP_REST_Response(array('success' => true, 'id' => $post_id), 200);
        } catch (Exception $e) {
            error_log('CLAWS ERROR in create_contact: ' . $e->getMessage());
            error_log('CLAWS ERROR trace: ' . $e->getTraceAsString());
            return new WP_Error('create_failed', 'Could not create contact: ' . $e->getMessage(), array('status' => 500));
        }
    }
    
    public function update_contact($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            
            // Validate: must have either email or phone
            if (empty($params['email']) && empty($params['phone'])) {
                return new WP_Error('validation_error', 'Either email or phone is required', array('status' => 400));
            }
            
            $full_name = trim($params['first_name'] . ' ' . $params['last_name']);
            
            wp_update_post(array(
                'ID' => $id,
                'post_title' => $full_name
            ));
            
            update_post_meta($id, 'first_name', sanitize_text_field($params['first_name']));
            update_post_meta($id, 'last_name', sanitize_text_field($params['last_name']));
            update_post_meta($id, 'email', sanitize_email($params['email']));
            update_post_meta($id, 'phone', sanitize_text_field($params['phone']));
            update_post_meta($id, 'birthday', sanitize_text_field($params['birthday']));
            $do_not_contact = (!empty($params['do_not_contact']) && in_array($params['do_not_contact'], array(true, 'true', '1', 1, 'yes', 'on'), true));
            update_post_meta($id, 'do_not_contact', $do_not_contact ? '1' : '0');
            update_post_meta($id, 'notes', sanitize_textarea_field($params['notes']));
            update_post_meta($id, 'contact_type', sanitize_text_field($params['contact_type']));
            update_post_meta($id, 'username', sanitize_text_field($params['username']));
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('update_failed', 'Could not update contact', array('status' => 500));
        }
    }
    
    public function delete_contact($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            $reason = sanitize_textarea_field($params['reason']);
            
            if (empty($reason)) {
                return new WP_Error('missing_reason', 'Deletion reason is required', array('status' => 400));
            }
            
            $current_user = wp_get_current_user();
            
            // Soft delete - mark as deleted but keep in database
            update_post_meta($id, 'status', 'deleted');
            update_post_meta($id, 'deletion_notes', $reason);
            update_post_meta($id, 'deleted_by', $current_user->display_name);
            update_post_meta($id, 'deleted_date', current_time('mysql'));
            
            claws_log("Contact #$id soft-deleted by {$current_user->display_name}. Reason: $reason");
            
            return new WP_REST_Response(array('success' => true), 200);
        } catch (Exception $e) {
            return new WP_Error('delete_failed', 'Could not delete contact', array('status' => 500));
        }
    }
    
    public function elevate_contact_to_volunteer($request) {
        try {
            $id = intval($request->get_param('id'));
            $params = $request->get_json_params();
            $volunteer_type = sanitize_text_field($params['volunteer_type']);
            
            if (empty($volunteer_type)) {
                return new WP_Error('missing_type', 'Volunteer type is required', array('status' => 400));
            }
            
            // Get contact data
            $contact = get_post($id);
            $first_name = get_post_meta($id, 'first_name', true);
            $last_name = get_post_meta($id, 'last_name', true);
            $email = get_post_meta($id, 'email', true);
            $phone = get_post_meta($id, 'phone', true);
            $birthday = get_post_meta($id, 'birthday', true);
            $notes = get_post_meta($id, 'notes', true);
            
            $current_user = wp_get_current_user();
            $full_name = $contact->post_title;
            
            // Create volunteer application with approved status
            $app_id = wp_insert_post(array(
                'post_type' => 'claws_volunteer_app',
                'post_title' => $full_name,
                'post_status' => 'publish'
            ));
            
            if (is_wp_error($app_id)) {
                return new WP_Error('create_failed', 'Could not create volunteer application', array('status' => 500));
            }
            
            // Copy all contact data to volunteer app
            update_post_meta($app_id, 'first_name', $first_name);
            update_post_meta($app_id, 'last_name', $last_name);
            update_post_meta($app_id, 'email', $email);
            update_post_meta($app_id, 'phone', $phone);
            update_post_meta($app_id, 'birthday', $birthday);
            update_post_meta($app_id, 'notes', $notes);
            update_post_meta($app_id, 'volunteer_type', $volunteer_type);
            update_post_meta($app_id, 'status', 'approved');
            update_post_meta($app_id, 'reviewed_by', $current_user->display_name);
            update_post_meta($app_id, 'reviewed_date', current_time('mysql'));
            update_post_meta($app_id, 'elevated_from_contact', $id);
            
            // Soft delete the contact
            update_post_meta($id, 'status', 'elevated');
            update_post_meta($id, 'elevated_to_volunteer', $app_id);
            update_post_meta($id, 'elevated_date', current_time('mysql'));
            update_post_meta($id, 'elevated_by', $current_user->display_name);
            
            claws_log("Contact #$id elevated to volunteer by {$current_user->display_name}. New volunteer app #$app_id");
            
            return new WP_REST_Response(array('success' => true, 'volunteer_id' => $app_id), 200);
        } catch (Exception $e) {
            return new WP_Error('elevate_failed', 'Could not elevate contact', array('status' => 500));
        }
    }
    
    public function match_username_by_email($request) {
        try {
            $params = $request->get_json_params();
            $email = sanitize_email($params['email']);
            $record_id = intval($params['record_id']);
            $record_type = sanitize_text_field($params['record_type']);
            
            if (empty($email)) {
                return new WP_Error('missing_email', 'Email is required', array('status' => 400));
            }
            
            // Search WordPress users by email
            $user = get_user_by('email', $email);
            
            if ($user) {
                // Found matching user - update the record with username
                $post_type = $record_type === 'contact' ? 'claws_contact' : 'claws_volunteer_app';
                update_post_meta($record_id, 'username', $user->user_login);
                
                claws_log("Auto-matched username '{$user->user_login}' for $record_type #$record_id based on email: $email");
                
                return new WP_REST_Response(array(
                    'success' => true,
                    'username' => $user->user_login,
                    'message' => "Found matching user: {$user->user_login}"
                ), 200);
            } else {
                return new WP_REST_Response(array(
                    'success' => false,
                    'message' => "No WordPress user found with email: $email"
                ), 200);
            }
        } catch (Exception $e) {
            return new WP_Error('match_failed', 'Could not match username', array('status' => 500));
        }
    }
}
?>