<?php
/**
 * Election_Controller — سامانه هوادران v3: صندوق‌محور + فازها + GIS/ERP
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class Election_Controller {

    public static function register_routes(): void {
        $ns = 'acc/v1';
        $pub = static fn() => true;
        $auth = static fn() => is_user_logged_in();

        register_rest_route( $ns, '/public/election/meta', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_meta' ], 'permission_callback' => $pub,
        ] );

        register_rest_route( $ns, '/election/me', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_me' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/dashboard', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_dashboard' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/my-hq', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_dashboard' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/phase', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_phase' ], 'permission_callback' => $auth,
        ] );

        register_rest_route( $ns, '/election/stations', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_stations' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/my-stations', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_my_stations' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/pois', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'get_pois' ], 'permission_callback' => $auth ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'post_poi' ], 'permission_callback' => $auth ],
        ] );
        register_rest_route( $ns, '/election/tasks', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_tasks' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/tasks/(?P<id>\d+)/complete', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'complete_task' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/briefings', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_briefings' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/shipments', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_shipments' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/shipments/(?P<id>\d+)/confirm', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'confirm_shipment' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/org-structure', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_org_structure' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/departments', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_departments' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/my-department', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_my_department' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/dept-work', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'get_dept_work' ], 'permission_callback' => $auth ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'post_dept_work' ], 'permission_callback' => $auth ],
        ] );
        register_rest_route( $ns, '/election/dept-work/(?P<id>\d+)/complete', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'complete_dept_work' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/banners', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'get_banners' ], 'permission_callback' => $auth ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'post_banner' ], 'permission_callback' => $auth ],
        ] );
        register_rest_route( $ns, '/election/banners/(?P<id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'update_banner' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/warehouse', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_warehouse' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/warehouse/issue', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_warehouse_issue' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/public/election/onboarding/request', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'public_onboarding_request' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/public/election/onboarding/complete', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'public_onboarding_complete' ], 'permission_callback' => $pub,
        ] );

        register_rest_route( $ns, '/election/map', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_map' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/pickable-stations', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_pickable_stations' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/my-stations/pick', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_pick_stations' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/warehouse/ship', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_warehouse_ship' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/county-portal', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_county_portal' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/committee-portal', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_committee_portal' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/admin/onboarding', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_onboarding' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/districts', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_districts' ], 'permission_callback' => $auth,
        ] );

        register_rest_route( $ns, '/election/content', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_content' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/packages', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_packages' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/reports', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'get_reports' ], 'permission_callback' => $auth ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'post_report' ], 'permission_callback' => $auth ],
        ] );

        register_rest_route( $ns, '/election/admin/gis-intel', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'admin_gis_intel' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/erp-intel', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'admin_erp_intel' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/assign-stations', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_assign_stations' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/briefings', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_post_briefing' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/phase', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_set_phase' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/sms', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_sms' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/financial', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_financial' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/financial/transactions', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_financial_tx' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/financial/budget', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_financial_budget' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/admin/segments', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'admin_segments' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/import-segments', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_import_segments' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/public/election/candidate-hub', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'public_candidate_hub' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/public/election/candidate-hub/chat', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'public_candidate_chat' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/public/election/candidate/suggestions', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'public_candidate_suggestion' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/election/candidate/suggestions', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_candidate_suggestion' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/admin/candidate-suggestions', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'admin_candidate_suggestions' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/candidate-suggestions/(?P<id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'admin_review_suggestion' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ],
        ] );
        register_rest_route( $ns, '/election/admin/sms-config', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'get_sms_config' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ] ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'post_sms_config' ], 'permission_callback' => [ __CLASS__, 'perm_manage' ] ],
        ] );
        register_rest_route( $ns, '/public/election/integrity', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'public_integrity' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/election/integrity', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_integrity' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/sectors', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'get_sectors' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/public/election/sectors/chat', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'public_sector_chat' ], 'permission_callback' => $pub,
        ] );
        register_rest_route( $ns, '/election/sectors/engage', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'post_sector_engage' ], 'permission_callback' => $auth,
        ] );

        /* ABC — بهای تمام‌شده فعالیت کمپین */
        register_rest_route( $ns, '/election/acct/activities', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'acct_activities' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/acct/campaigns', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'acct_campaigns' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/acct/cost-graph', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'acct_cost_graph' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/acct/activity-cost/(?P<campaign_id>\d+)', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'acct_activity_cost' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/acct/allocate/(?P<campaign_id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'acct_allocate' ], 'permission_callback' => $auth,
        ] );
        register_rest_route( $ns, '/election/acct/crew/(?P<campaign_id>\d+)', [
            [
                'methods' => 'GET', 'callback' => [ __CLASS__, 'acct_get_crew' ], 'permission_callback' => $auth,
            ],
            [
                'methods' => 'POST', 'callback' => [ __CLASS__, 'acct_save_crew' ], 'permission_callback' => $auth,
            ],
        ] );
    }

    public static function perm_manage(): bool {
        if ( ! is_user_logged_in() ) return false;
        require_once ACC_PATH . 'includes/helpers/election-havadaran.php';
        return Election_Havadaran::can_manage( acl_current_user_id() );
    }

    private static function helper(): string {
        require_once ACC_PATH . 'includes/helpers/election-havadaran.php';
        return Election_Havadaran::class;
    }

    private static function guard_access(): ?WP_REST_Response {
        $H = self::helper();
        $uid = acl_current_user_id();
        if ( ! $H::can_access( $uid ) ) {
            return new WP_REST_Response( [ 'message' => 'دسترسی ندارید' ], 403 );
        }
        return null;
    }

    public static function get_meta(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [
            'data' => [
                'stats'      => $H::stats(),
                'phase'      => $H::phase_info(),
                'phases'     => $H::PHASES,
                'poi_types'  => $H::POI_TYPES,
                'departments'=> array_map( fn( $slug, $d ) => [
                    'slug' => $slug, 'title' => $d['title'], 'icon' => $d['icon'],
                    'work_subject' => $d['work_subject'],
                    'bureau' => Election_Havadaran::dept_bureau_slug( $slug ),
                ], array_keys( $H::department_catalog() ), $H::department_catalog() ),
                'org_structure' => $H::org_admin_structure(),
                'field_workflow'=> $H::field_workflow_steps(),
                'warehouse_categories' => $H::WAREHOUSE_CATEGORIES,
                'banner_spot_types'    => $H::BANNER_SPOT_TYPES,
                'county_zones'         => $H::COUNTY_ZONES,
                'committee_types'      => $H::COMMITTEE_TYPES,
                'max_stations'         => $H::MAX_STATIONS_PER_SUPPORTER,
                'segment_progress'     => $H::segment_stats(),
                'sms_config'           => $H::sms_config(),
                'budget_categories'    => $H::BUDGET_CATEGORIES,
                'candidate_hub'        => $H::hub_payload(),
                'integrity'            => ( $integrity = $H::integrity_scorecard() ),
                'integrity_certificate'=> $integrity['certificate'],
                'integrity_average'    => $integrity['average'],
                'sector_count'         => count( $H::sector_catalog() ),
                'tagline'    => 'ستاد انتخابات — ساختار اداری موقت',
                'gis_linked' => $H::gis_tables_exist(),
            ],
        ] );
    }

    public static function get_me(): WP_REST_Response {
        global $wpdb;
        $H = self::helper();
        $uid = acl_current_user_id();
        $user = $wpdb->get_row( $wpdb->prepare(
            "SELECT ID, display_name, user_login FROM {$wpdb->users} WHERE ID = %d", $uid
        ), ARRAY_A );
        return new WP_REST_Response( [
            'data' => [
                'user'       => $user,
                'can_manage' => $H::can_manage( $uid ),
                'stations'   => $H::user_stations( $uid ),
            ],
        ] );
    }

    public static function get_dashboard(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::department_dashboard( acl_current_user_id() ) ] );
    }

    public static function get_phase(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::phase_info() ] );
    }

    public static function get_stations(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        if ( $H::can_manage( $uid ) ) {
            return new WP_REST_Response( [ 'data' => $H::list_stations_enriched() ] );
        }
        return new WP_REST_Response( [ 'data' => $H::user_stations( $uid ) ] );
    }

    public static function get_my_stations(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::user_stations( acl_current_user_id() ) ] );
    }

    public static function get_pois( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        $sid = (int) $req->get_param( 'station_id' );
        if ( $H::can_manage( $uid ) ) {
            return new WP_REST_Response( [ 'data' => $H::list_pois( $sid ?: null ) ] );
        }
        return new WP_REST_Response( [ 'data' => $H::list_pois( $sid ?: null, $uid ) ] );
    }

    public static function post_poi( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::add_poi( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function get_tasks(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_tasks( acl_current_user_id() ) ] );
    }

    public static function complete_task( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::complete_task( acl_current_user_id(), (int) $req['id'] );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_briefings(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_briefings( acl_current_user_id() ) ] );
    }

    public static function get_shipments(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_shipments( acl_current_user_id() ) ] );
    }

    public static function confirm_shipment( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::confirm_shipment( acl_current_user_id(), (int) $req['id'] );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_org(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::org_tree() ] );
    }

    public static function get_org_structure(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::org_admin_structure() ] );
    }

    public static function get_departments(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        return new WP_REST_Response( [
            'data' => $H::can_manage( $uid )
                ? array_map( fn( $slug, $d ) => array_merge( $d, [ 'slug' => $slug, 'work_count' => $H::dept_work_count( $slug ) ] ), array_keys( $H::department_catalog() ), $H::department_catalog() )
                : $H::list_departments_for_user( $uid ),
        ] );
    }

    public static function get_my_department(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::user_department( acl_current_user_id() ) ] );
    }

    public static function get_dept_work( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $slug = sanitize_key( $req->get_param( 'dept_slug' ) ?: '' );
        return new WP_REST_Response( [ 'data' => $H::list_dept_work( acl_current_user_id(), $slug ?: null ) ] );
    }

    public static function post_dept_work( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::add_dept_work( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function complete_dept_work( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::complete_dept_work( acl_current_user_id(), (int) $req['id'] );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_districts(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_districts() ] );
    }

    public static function get_content(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::content_for_user( acl_current_user_id() ) ] );
    }

    public static function get_packages(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_packages( null ) ] );
    }

    public static function get_reports(): WP_REST_Response {
        global $wpdb;
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        $t = $H::reports_table();
        if ( $H::can_manage( $uid ) ) {
            $rows = $wpdb->get_results( "SELECT * FROM {$t} ORDER BY id DESC LIMIT 100", ARRAY_A ) ?: [];
        } else {
            $rows = $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$t} WHERE user_id = %d ORDER BY id DESC LIMIT 50", $uid
            ), ARRAY_A ) ?: [];
        }
        return new WP_REST_Response( [ 'data' => $rows ] );
    }

    public static function post_report( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::submit_report( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function admin_gis_intel(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::admin_gis_intel() ] );
    }

    public static function admin_erp_intel(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::admin_erp_intel() ] );
    }

    public static function admin_assign_stations( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $p = (array) $req->get_json_params();
        $uid = (int) ( $p['user_id'] ?? 0 );
        $sids = (array) ( $p['station_ids'] ?? [] );
        $role = sanitize_key( $p['role'] ?? 'supporter' );
        if ( ! $uid || ! $sids ) {
            return new WP_REST_Response( [ 'message' => 'user_id و station_ids الزامی' ], 400 );
        }
        $res = $H::assign_stations_to_user( $uid, $sids, $role );
        return new WP_REST_Response( $res );
    }

    public static function admin_post_briefing( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $res = $H::add_briefing( (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function admin_set_phase( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $H = self::helper();
        $phase = sanitize_key( ( $req->get_json_params()['current_phase'] ?? '' ) );
        if ( ! isset( $H::PHASES[ $phase ] ) ) {
            return new WP_REST_Response( [ 'message' => 'فاز نامعتبر' ], 400 );
        }
        $t = $H::phase_config_table();
        $wpdb->query( $wpdb->prepare( "UPDATE {$t} SET current_phase = %s ORDER BY id DESC LIMIT 1", $phase ) );
        return new WP_REST_Response( [ 'success' => true, 'phase' => $H::phase_info() ] );
    }

    public static function post_sms( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        if ( ! $H::can_manage( acl_current_user_id() ) ) {
            return new WP_REST_Response( [ 'message' => 'دسترسی ندارید' ], 403 );
        }
        $res = $H::queue_sms( (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function get_banners( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $uid = acl_current_user_id();
        $sid = (int) $req->get_param( 'station_id' );
        if ( $H::can_manage( $uid ) || $H::portal_mode( $uid ) === 'dept' ) {
            return new WP_REST_Response( [ 'data' => $H::list_banner_spots( $sid ?: null ) ] );
        }
        return new WP_REST_Response( [ 'data' => $H::list_banner_spots( $sid ?: null, $uid ) ] );
    }

    public static function post_banner( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $res = $H::add_banner_spot( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function update_banner( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $res = $H::update_banner_spot( acl_current_user_id(), (int) $req['id'], (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_warehouse(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [
            'data' => [
                'summary' => $H::warehouse_summary(),
                'items'   => $H::list_warehouse_items(),
            ],
        ] );
    }

    public static function post_warehouse_issue( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $res = $H::issue_warehouse_item( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function get_map(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::supporter_map_data( acl_current_user_id() ) ] );
    }

    public static function get_pickable_stations(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::list_pickable_stations( acl_current_user_id() ) ] );
    }

    public static function post_pick_stations( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $p   = (array) $req->get_json_params();
        $res = $H::pick_stations(
            acl_current_user_id(),
            (array) ( $p['station_ids'] ?? [] ),
            sanitize_key( $p['mode'] ?? 'add' )
        );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function post_warehouse_ship( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H   = self::helper();
        $res = $H::issue_warehouse_and_ship( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function get_county_portal(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::county_portal_data( acl_current_user_id() ) ] );
    }

    public static function get_committee_portal(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::committee_portal_data( acl_current_user_id() ) ] );
    }

    public static function public_onboarding_request( WP_REST_Request $req ): WP_REST_Response {
        $H   = self::helper();
        $p   = (array) $req->get_json_params();
        $res = $H::request_onboarding( $p['phone'] ?? '' );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function public_onboarding_complete( WP_REST_Request $req ): WP_REST_Response {
        $H   = self::helper();
        $p   = (array) $req->get_json_params();
        $res = $H::complete_onboarding( $p['phone'] ?? '', $p['code'] ?? '', $p['name'] ?? '' );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function admin_onboarding( WP_REST_Request $req ): WP_REST_Response {
        $H   = self::helper();
        $res = $H::admin_send_onboarding( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_financial(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        if ( ! $H::can_financial( $uid ) && ! $H::can_manage( $uid ) ) {
            return new WP_REST_Response( [ 'message' => 'دسترسی مالی ندارید' ], 403 );
        }
        return new WP_REST_Response( [ 'data' => $H::financial_dashboard() ] );
    }

    public static function post_financial_tx( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::add_transaction( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function post_financial_budget( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::update_budget_line( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function admin_segments( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $limit = (int) ( $req->get_param( 'limit' ) ?: 100 );
        $offset = (int) ( $req->get_param( 'offset' ) ?: 0 );
        return new WP_REST_Response( [ 'data' => $H::admin_list_segments( [ 'limit' => $limit, 'offset' => $offset ] ) ] );
    }

    public static function admin_import_segments( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $p = (array) $req->get_json_params();
        $res = $H::import_segments_from_gis( ! empty( $p['replace'] ) );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_sms_config(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::sms_config() ] );
    }

    public static function post_sms_config( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $res = $H::save_sms_config( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function public_candidate_hub(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::hub_payload() ] );
    }

    public static function public_candidate_chat( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $p = (array) $req->get_json_params();
        $res = $H::candidate_chat(
            $p['message'] ?? '',
            sanitize_key( $p['section'] ?? 'chat' ),
            (array) ( $p['history'] ?? [] )
        );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function public_candidate_suggestion( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $uid = is_user_logged_in() ? acl_current_user_id() : null;
        $res = $H::submit_candidate_suggestion( (array) $req->get_json_params(), $uid );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function post_candidate_suggestion( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::submit_candidate_suggestion( (array) $req->get_json_params(), acl_current_user_id() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function admin_candidate_suggestions(): WP_REST_Response {
        $H = self::helper();
        return new WP_REST_Response( [
            'data' => [
                'items'  => $H::list_candidate_suggestions( 100 ),
                'stats'  => [
                    'total' => $H::count_suggestions(),
                    'new'   => $H::count_suggestions( 'new' ),
                ],
                'sections' => $H::CANDIDATE_SECTIONS,
            ],
        ] );
    }

    public static function admin_review_suggestion( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $p = (array) $req->get_json_params();
        $res = $H::review_suggestion(
            acl_current_user_id(),
            (int) $req['id'],
            sanitize_key( $p['status'] ?? 'reviewed' )
        );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function public_integrity(): WP_REST_Response {
        $H = self::helper();
        $sc = $H::integrity_scorecard();
        return new WP_REST_Response( [
            'data' => [
                'certificate' => $sc['certificate'],
                'average'     => $sc['average'],
                'framework'   => $sc['framework'],
                'pillars'     => array_map( fn( $p ) => [
                    'code' => $p['code'], 'title' => $p['title'], 'score' => $p['score'], 'level' => $p['level'],
                ], $sc['pillars'] ),
            ],
        ] );
    }

    public static function get_integrity(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::integrity_scorecard() ] );
    }

    public static function get_sectors(): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        return new WP_REST_Response( [ 'data' => $H::sector_matrix_payload() ] );
    }

    public static function public_sector_chat( WP_REST_Request $req ): WP_REST_Response {
        $H = self::helper();
        $p = (array) $req->get_json_params();
        $res = $H::sector_chat( $p['message'] ?? '', sanitize_key( $p['sector_slug'] ?? '' ) );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function post_sector_engage( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $res = $H::log_sector_engagement( acl_current_user_id(), (array) $req->get_json_params() );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    /* ── حسابداری ABC کمپین ─────────────────────────── */

    private static function _abc(): void {
        require_once ACC_PATH . 'includes/helpers/election-activity-cost.php';
        Election_Activity_Cost::ensure_tables();
    }

    private static function guard_financial_or_manage(): ?WP_REST_Response {
        if ( $err = self::guard_access() ) return $err;
        $H = self::helper();
        $uid = acl_current_user_id();
        if ( ! $H::can_financial( $uid ) && ! $H::can_manage( $uid ) ) {
            return new WP_REST_Response( [ 'message' => 'دسترسی مالی ندارید' ], 403 );
        }
        return null;
    }

    public static function acct_activities( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Election_Activity_Cost::list_activities( true ),
            'roles'   => Election_Activity_Cost::role_labels(),
        ] );
    }

    public static function acct_campaigns( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Election_Activity_Cost::list_campaigns(),
        ] );
    }

    public static function acct_cost_graph( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        $data = Election_Activity_Cost::cost_graph( [
            'campaign_id' => (int) ( $req->get_param( 'campaign_id' ) ?: 0 ),
        ] );
        return new WP_REST_Response( [ 'success' => true, 'data' => $data ] );
    }

    public static function acct_activity_cost( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        $id = (int) $req['campaign_id'];
        $row = Election_Activity_Cost::get_campaign( $id );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'کمپین یافت نشد' ], 404 );
        }
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Election_Activity_Cost::allocate( $row ),
        ] );
    }

    public static function acct_allocate( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        $id = (int) $req['campaign_id'];
        $row = Election_Activity_Cost::get_campaign( $id );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'کمپین یافت نشد' ], 404 );
        }
        $alloc = Election_Activity_Cost::allocate( $row );
        Election_Activity_Cost::persist( $id, $alloc );
        return new WP_REST_Response( [
            'success' => true,
            'message' => 'تخصیص فعالیت کمپین ذخیره شد',
            'data'    => $alloc,
        ] );
    }

    public static function acct_get_crew( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        $id = (int) $req['campaign_id'];
        $row = Election_Activity_Cost::get_campaign( $id );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'کمپین یافت نشد' ], 404 );
        }
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Election_Activity_Cost::get_crew( $id ),
        ] );
    }

    public static function acct_save_crew( WP_REST_Request $req ): WP_REST_Response {
        if ( $err = self::guard_financial_or_manage() ) return $err;
        self::_abc();
        $id = (int) $req['campaign_id'];
        $row = Election_Activity_Cost::get_campaign( $id );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'کمپین یافت نشد' ], 404 );
        }
        $members = $req->get_param( 'members' );
        if ( ! is_array( $members ) ) {
            $p = (array) $req->get_json_params();
            $members = $p['members'] ?? [];
        }
        if ( ! is_array( $members ) ) $members = [];
        return new WP_REST_Response( Election_Activity_Cost::save_crew( $id, $members ) );
    }
}
