<?php
/**
 * Arag_Erp_Controller — پنل ERP فروشگاه عرقیات
 * حسابداری · CRM · حمل‌ونقل
 */
if ( ! defined( 'ABSPATH' ) ) exit;

require_once ACC_PATH . 'includes/helpers/arag-erp.php';
require_once ACC_PATH . 'includes/helpers/arag-expense.php';
require_once ACC_PATH . 'includes/helpers/arag-shop-accounting.php';

class Arag_Erp_Controller {

    public static function register_routes(): void {
        $ns  = 'acc/v1';
        $jwt = [ __CLASS__, 'require_jwt' ];

        register_rest_route( $ns, '/arag/erp/dashboard', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'dashboard' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/orders', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'list_orders' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/orders/(?P<id>\d+)/sync', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'sync_order' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/erp/accounting/pending', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'accounting_pending' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/accounting/post/(?P<order_id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'accounting_post' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/accounting/config', [
            [ 'methods' => 'GET', 'callback' => [ __CLASS__, 'get_config' ], 'permission_callback' => $jwt ],
            [ 'methods' => 'PUT', 'callback' => [ __CLASS__, 'save_config' ], 'permission_callback' => $jwt ],
        ] );
        register_rest_route( $ns, '/arag/erp/accounting/portal', [
            [ 'methods' => 'GET', 'callback' => [ __CLASS__, 'get_portal' ], 'permission_callback' => $jwt ],
            [ 'methods' => 'PUT', 'callback' => [ __CLASS__, 'save_portal' ], 'permission_callback' => $jwt ],
        ] );

        register_rest_route( $ns, '/arag/erp/crm/leads', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'crm_leads' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/crm/leads/(?P<id>\d+)', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'crm_lead_detail' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/crm/summary', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'crm_summary' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/erp/shipping/shipments', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shipping_list' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/shipping/orders-pending', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shipping_orders_pending' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/shipping/methods', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shipping_methods' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/shipping/create', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'shipping_create' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/shipping/(?P<id>\d+)/advance', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'shipping_advance' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/shipping/(?P<id>\d+)/patch', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'shipping_patch' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/erp/inventory/stock', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'inventory_stock' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/inventory/vouchers', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'inventory_vouchers' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/erp/me/role', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'me_role' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/erp/finance/summary', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'finance_summary' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/finance/monthly', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'finance_monthly' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/expenses', [
            [ 'methods' => 'GET',  'callback' => [ __CLASS__, 'expenses_list' ], 'permission_callback' => $jwt ],
            [ 'methods' => 'POST', 'callback' => [ __CLASS__, 'expenses_create' ], 'permission_callback' => $jwt ],
        ] );
        register_rest_route( $ns, '/arag/erp/expenses/(?P<id>\d+)', [
            'methods' => 'DELETE', 'callback' => [ __CLASS__, 'expenses_delete' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/erp/mizaj/stats', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'mizaj_stats' ], 'permission_callback' => $jwt,
        ] );

        /* ── حسابداری فروش فروشگاه (دفتر کل · اسناد · گزارش) ── */
        register_rest_route( $ns, '/arag/shop-acct/meta', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_meta' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/dashboard', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_dashboard' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/documents', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_documents' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/documents/(?P<id>\d+)', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_document_detail' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/ledger', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_ledger' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/trial-balance', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_trial_balance' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/income-statement', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_income_statement' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/chart', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_chart' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/pending', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_pending' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/post/(?P<order_id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'shop_acct_post' ], 'permission_callback' => $jwt,
        ] );

        register_rest_route( $ns, '/arag/shop-acct/activities', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_activities' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/cost-graph', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_cost_graph' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/activity-cost/(?P<order_id>\d+)', [
            'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_activity_cost' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/allocate/(?P<order_id>\d+)', [
            'methods' => 'POST', 'callback' => [ __CLASS__, 'shop_acct_allocate' ], 'permission_callback' => $jwt,
        ] );
        register_rest_route( $ns, '/arag/shop-acct/crew/(?P<order_id>\d+)', [
            [ 'methods' => 'GET', 'callback' => [ __CLASS__, 'shop_acct_get_crew' ], 'permission_callback' => $jwt ],
            [ 'methods' => 'PUT', 'callback' => [ __CLASS__, 'shop_acct_save_crew' ], 'permission_callback' => $jwt ],
        ] );
    }

    /** ورود با JWT الزامی — حتی در حالت mock توسعه */
    public static function require_jwt( WP_REST_Request $req ): bool {
        if ( ! function_exists( '_acc_jwt_user_id_from_request' ) ) {
            return false;
        }
        return _acc_jwt_user_id_from_request() > 0;
    }

    private static function deny(): ?WP_REST_Response {
        if ( ! Arag_Erp::erp_can_view() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'دسترسی ERP فروشگاه ندارید' ], 403 );
        }
        return null;
    }

    public static function me_role( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [
            'role'          => Arag_Erp::erp_can_post() ? 'accountant' : 'viewer',
            'is_accountant' => Arag_Erp::erp_can_post(),
            'can_view'      => Arag_Erp::erp_can_view(),
            'portal'        => Arag_Erp::portal_settings(),
        ] );
    }

    public static function dashboard( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;

        $orders_today = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$pre}arag_orders WHERE DATE(created_at) = CURDATE()"
        );
        $orders_paid = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$pre}arag_orders WHERE payment_status IN ('paid','cod')"
        );
        $pending_acc = count( Arag_Erp::pending_accounting_queue( 100 ) );

        $crm_shop = 0;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_leads'" ) === "{$pre}crm_leads" ) {
            $crm_shop = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$pre}crm_leads WHERE lead_channel = 'shop'"
            );
        }

        $ship_active = 0;
        $inv_products = 0;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}ship_shipments'" ) === "{$pre}ship_shipments" ) {
            $ship_active = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$pre}ship_shipments
                 WHERE ref_type = 'arag_order' AND status NOT IN ('delivered','cancelled','returned')"
            );
        }
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}inv_stock'" ) === "{$pre}inv_stock" ) {
            $wh = Arag_Erp::default_warehouse_id();
            if ( $wh > 0 ) {
                $inv_products = (int) $wpdb->get_var( $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$pre}inv_stock WHERE warehouse_id = %d AND qty > 0", $wh
                ) );
            }
        }

        $recent = $wpdb->get_results(
            "SELECT id, order_number, subtotal, payment_status, order_status, billing_name,
                    crm_lead_id, ship_shipment_id, acc_event_id, created_at
             FROM {$pre}arag_orders ORDER BY id DESC LIMIT 10",
            ARRAY_A
        ) ?: [];

        return new WP_REST_Response( [
            'success' => true,
            'stats'   => [
                'orders_today'      => $orders_today,
                'orders_paid'       => $orders_paid,
                'pending_accounting'=> $pending_acc,
                'crm_shop_leads'    => $crm_shop,
                'ship_active'       => $ship_active,
                'inv_skus_in_stock' => $inv_products,
            ],
            'recent_orders' => $recent,
            'portal'        => Arag_Erp::portal_settings(),
        ] );
    }

    public static function list_orders( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        $status = sanitize_text_field( $req->get_param( 'payment_status' ) ?? '' );
        $where  = $status ? $wpdb->prepare( 'WHERE payment_status = %s', $status ) : '';
        $rows = $wpdb->get_results(
            "SELECT id, order_number, subtotal, payment_status, order_status, shipping_method,
                    billing_name, billing_phone, crm_lead_id, ship_shipment_id, acc_event_id,
                    erp_synced_at, created_at
             FROM {$pre}arag_orders {$where}
             ORDER BY id DESC LIMIT 100",
            ARRAY_A
        ) ?: [];
        return new WP_REST_Response( [ 'data' => $rows ] );
    }

    public static function sync_order( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $id = (int) $req->get_param( 'id' );
        $res = Arag_Erp::on_order_confirmed( $id );
        $code = ! empty( $res['success'] ) ? 200 : 400;
        return new WP_REST_Response( $res, $code );
    }

    public static function accounting_pending( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [
            'data'     => Arag_Erp::pending_accounting_queue( 50 ),
            'can_post' => Arag_Erp::erp_can_post(),
        ] );
    }

    public static function accounting_post( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'مجوز صدور سند ندارید' ], 403 );
        }
        $res = Arag_Erp::post_order_by_accountant( (int) $req->get_param( 'order_id' ) );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function get_config( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [
            'config' => Arag_Erp::get_config(),
            'can_post' => Arag_Erp::erp_can_post(),
        ] );
    }

    public static function save_config( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'مجوز ویرایش ندارید' ], 403 );
        }
        $body = $req->get_json_params() ?: [];
        Arag_Erp::save_config( $body );
        return new WP_REST_Response( [ 'success' => true, 'config' => Arag_Erp::get_config() ] );
    }

    public static function get_portal( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [ 'portal' => Arag_Erp::portal_settings() ] );
    }

    public static function save_portal( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'مجوز ویرایش ندارید' ], 403 );
        }
        $body = $req->get_json_params() ?: [];
        Arag_Erp::save_portal_settings( $body );
        return new WP_REST_Response( [ 'success' => true, 'portal' => Arag_Erp::portal_settings() ] );
    }

    public static function crm_lead_detail( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        $id  = (int) $req->get_param( 'id' );
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_leads'" ) !== "{$pre}crm_leads" ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'CRM نصب نیست' ], 404 );
        }
        $lead = $wpdb->get_row( $wpdb->prepare(
            "SELECT l.*,
                    o.order_number, o.subtotal AS order_total, o.payment_status, o.shipping_method,
                    o.billing_address, o.billing_city
             FROM {$pre}crm_leads l
             LEFT JOIN {$pre}arag_orders o ON o.id = l.arag_order_id
             WHERE l.id = %d AND (l.lead_channel = 'shop' OR l.arag_order_id IS NOT NULL)",
            $id
        ), ARRAY_A );
        if ( ! $lead ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'لید یافت نشد' ], 404 );
        }
        $lead['activities'] = [];
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_activities'" ) === "{$pre}crm_activities" ) {
            $lead['activities'] = $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$pre}crm_activities WHERE lead_id = %d ORDER BY activity_date DESC LIMIT 30",
                $id
            ), ARRAY_A ) ?: [];
        }
        $lead['reminders'] = [];
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_reminders'" ) === "{$pre}crm_reminders" ) {
            $lead['reminders'] = $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$pre}crm_reminders WHERE lead_id = %d ORDER BY due_date ASC LIMIT 10",
                $id
            ), ARRAY_A ) ?: [];
        }
        $lead['status_label'] = self::_crm_status_label( $lead['status'] ?? '' );
        $lead['portal_url']   = site_url( '' ) . '#crm/leads/' . $id;
        return new WP_REST_Response( [ 'success' => true, 'data' => $lead ] );
    }

    public static function crm_summary( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_leads'" ) !== "{$pre}crm_leads" ) {
            return new WP_REST_Response( [ 'data' => [] ] );
        }
        $total = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$pre}crm_leads WHERE lead_channel = 'shop' OR arag_order_id IS NOT NULL"
        );
        $converted = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$pre}crm_leads WHERE (lead_channel = 'shop' OR arag_order_id IS NOT NULL) AND status = 'converted'"
        );
        $activities = 0;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_activities'" ) === "{$pre}crm_activities" ) {
            $activities = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$pre}crm_activities a
                 INNER JOIN {$pre}crm_leads l ON l.id = a.lead_id
                 WHERE l.lead_channel = 'shop' OR l.arag_order_id IS NOT NULL"
            );
        }
        return new WP_REST_Response( [
            'data' => [
                'total_leads'    => $total,
                'converted'      => $converted,
                'activity_count' => $activities,
                'portal_crm_url' => site_url( '' ) . '#crm',
            ],
        ] );
    }

    private static function _crm_status_label( string $status ): string {
        $map = [
            'new_lead'    => 'لید جدید',
            'contacted'   => 'تماس گرفته',
            'negotiating' => 'در مذاکره',
            'converted'   => 'تبدیل به مشتری',
            'lost'        => 'از دست رفته',
            'on_hold'     => 'معلق',
        ];
        return $map[ $status ] ?? $status;
    }

    public static function crm_leads( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}crm_leads'" ) !== "{$pre}crm_leads" ) {
            return new WP_REST_Response( [ 'data' => [], 'message' => 'CRM نصب نیست' ] );
        }
        $rows = $wpdb->get_results(
            "SELECT l.*,
                    o.order_number, o.subtotal AS order_total,
                    (SELECT COUNT(*) FROM {$pre}crm_activities a WHERE a.lead_id = l.id) AS activity_count
             FROM {$pre}crm_leads l
             LEFT JOIN {$pre}arag_orders o ON o.id = l.arag_order_id
             WHERE l.lead_channel = 'shop' OR l.arag_order_id IS NOT NULL
             ORDER BY l.updated_at DESC
             LIMIT 100",
            ARRAY_A
        ) ?: [];
        foreach ( $rows as &$r ) {
            $r['status_label'] = self::_crm_status_label( $r['status'] ?? '' );
        }
        return new WP_REST_Response( [ 'data' => $rows ] );
    }

    public static function shipping_list( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        $rows = $wpdb->get_results(
            "SELECT s.*, m.name AS method_name, m.icon AS method_icon,
                    o.order_number, o.payment_status
             FROM {$pre}ship_shipments s
             LEFT JOIN {$pre}ship_methods m ON m.id = s.method_id
             LEFT JOIN {$pre}arag_orders o ON o.id = s.ref_id AND s.ref_type = 'arag_order'
             WHERE s.ref_type = 'arag_order'
             ORDER BY s.created_at DESC
             LIMIT 100",
            ARRAY_A
        ) ?: [];

        $flow = [
            'pending' => 'در انتظار', 'preparing' => 'آماده‌سازی', 'packed' => 'بسته‌بندی',
            'picked_up' => 'تحویل پیک', 'in_transit' => 'در حال حمل',
            'out_for_delivery' => 'ارسال نهایی', 'delivered' => 'تحویل شد',
            'failed' => 'ناموفق', 'returned' => 'مرجوع', 'cancelled' => 'لغو',
        ];
        foreach ( $rows as &$r ) {
            $r['status_label'] = $flow[ $r['status'] ] ?? $r['status'];
        }

        return new WP_REST_Response( [ 'data' => $rows, 'flow' => $flow ] );
    }

    public static function shipping_orders_pending( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        $rows = $wpdb->get_results(
            "SELECT id, order_number, billing_name, billing_phone, billing_address, billing_city,
                    shipping_method, subtotal, payment_status, order_status, created_at
             FROM {$pre}arag_orders
             WHERE ship_shipment_id IS NULL
               AND payment_status IN ('paid','cod','awaiting_transfer')
               AND order_status NOT IN ('cancelled')
             ORDER BY id DESC
             LIMIT 50",
            ARRAY_A
        ) ?: [];
        return new WP_REST_Response( [ 'data' => $rows ] );
    }

    public static function shipping_methods( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $pre = $wpdb->prefix;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}ship_methods'" ) !== "{$pre}ship_methods" ) {
            return new WP_REST_Response( [ 'data' => [] ] );
        }
        $rows = $wpdb->get_results(
            "SELECT id, code, name, icon, avg_days FROM {$pre}ship_methods WHERE is_active = 1 ORDER BY id",
            ARRAY_A
        ) ?: [];
        return new WP_REST_Response( [ 'data' => $rows ] );
    }

    public static function shipping_create( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $order_id = (int) ( $req->get_param( 'order_id' ) ?? 0 );
        if ( $order_id <= 0 ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'شناسه سفارش الزامی است' ], 400 );
        }
        $order = Arag_Erp::get_order( $order_id );
        if ( ! $order ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'سفارش یافت نشد' ], 404 );
        }
        if ( ! empty( $order['ship_shipment_id'] ) ) {
            return new WP_REST_Response( [
                'success'     => false,
                'message'     => 'برای این سفارش محموله قبلاً ثبت شده',
                'shipment_id' => (int) $order['ship_shipment_id'],
            ], 400 );
        }
        $res = Arag_Erp::create_shipment( $order );
        $tracking = sanitize_text_field( $req->get_param( 'tracking_code' ) ?? '' );
        $notes    = sanitize_textarea_field( $req->get_param( 'notes' ) ?? '' );
        if ( ! empty( $res['shipment_id'] ) && ( $tracking || $notes ) ) {
            global $wpdb;
            $patch = [];
            if ( $tracking ) {
                $patch['tracking_code'] = $tracking;
            }
            if ( $notes ) {
                $patch['notes'] = $notes;
            }
            $wpdb->update( $wpdb->prefix . 'ship_shipments', $patch, [ 'id' => (int) $res['shipment_id'] ] );
        }
        if ( ! empty( $res['success'] ) ) {
            global $wpdb;
            $wpdb->update( $wpdb->prefix . 'arag_orders', [
                'erp_synced_at' => current_time( 'mysql' ),
            ], [ 'id' => $order_id ] );
        }
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function shipping_patch( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $id = (int) $req->get_param( 'id' );
        $ship = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ship_shipments WHERE id = %d AND ref_type = 'arag_order'", $id
        ), ARRAY_A );
        if ( ! $ship ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'محموله یافت نشد' ], 404 );
        }
        $patch = [];
        if ( null !== $req->get_param( 'tracking_code' ) ) {
            $patch['tracking_code'] = sanitize_text_field( $req->get_param( 'tracking_code' ) );
        }
        if ( null !== $req->get_param( 'notes' ) ) {
            $patch['notes'] = sanitize_textarea_field( $req->get_param( 'notes' ) );
        }
        if ( $patch ) {
            $patch['updated_at'] = current_time( 'mysql' );
            $wpdb->update( $wpdb->prefix . 'ship_shipments', $patch, [ 'id' => $id ] );
        }
        return new WP_REST_Response( [ 'success' => true, 'message' => 'محموله به‌روز شد' ] );
    }

    public static function shipping_advance( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $id     = (int) $req->get_param( 'id' );
        $status = sanitize_text_field( $req->get_param( 'status' ) ?? '' );
        $note   = sanitize_textarea_field( $req->get_param( 'note' ) ?? '' );

        $res = Arag_Erp::advance_shop_shipment( $id, $status, $note );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    public static function inventory_stock( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [
            'data'       => Arag_Erp::inventory_stock_summary( 50 ),
            'warehouse'  => Arag_Erp::default_warehouse_id(),
            'config'     => Arag_Erp::get_config(),
        ] );
    }

    public static function inventory_vouchers( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        return new WP_REST_Response( [ 'data' => Arag_Erp::shop_inventory_vouchers( 30 ) ] );
    }

    public static function finance_summary( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $from = sanitize_text_field( $req->get_param( 'from' ) ?? '' ) ?: null;
        $to   = sanitize_text_field( $req->get_param( 'to' ) ?? '' ) ?: null;
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Expense::financial_graph( $from, $to ),
            'categories' => Arag_Expense::categories(),
        ] );
    }

    public static function finance_monthly( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $months = max( 3, min( 12, (int) ( $req->get_param( 'months' ) ?? 6 ) ) );
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Expense::monthly_series( $months ),
        ] );
    }

    public static function expenses_list( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        $from = sanitize_text_field( $req->get_param( 'from' ) ?? '' ) ?: null;
        $to   = sanitize_text_field( $req->get_param( 'to' ) ?? '' ) ?: null;
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Expense::list_expenses( 200, $from, $to ),
            'categories' => Arag_Expense::categories(),
        ] );
    }

    public static function expenses_create( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'فقط حسابدار می‌تواند هزینه ثبت کند' ], 403 );
        }
        $body = $req->get_json_params() ?: [];
        $uid  = Arag_Erp::erp_jwt_user_id();
        $res  = Arag_Expense::create( $body, $uid );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 201 : 400 );
    }

    public static function expenses_delete( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'دسترسی ندارید' ], 403 );
        }
        $id = (int) $req->get_param( 'id' );
        return new WP_REST_Response( [ 'success' => Arag_Expense::delete( $id ) ] );
    }

    public static function mizaj_stats( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        global $wpdb;
        $t = $wpdb->prefix . 'arag_mizaj_sessions';
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return new WP_REST_Response( [ 'success' => true, 'data' => [ 'total' => 0, 'by_type' => [] ] ] );
        }
        $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$t}" );
        $rows  = $wpdb->get_results(
            "SELECT result_type, COUNT(*) AS cnt FROM {$t} GROUP BY result_type ORDER BY cnt DESC",
            ARRAY_A
        ) ?: [];
        return new WP_REST_Response( [
            'success' => true,
            'data'    => [ 'total' => $total, 'by_type' => $rows ],
        ] );
    }

    /* ── Shop Accounting (compact GL) ─────────────────────── */

    private static function shop_acct_deny(): ?WP_REST_Response {
        if ( ! Arag_Erp::erp_can_view() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'دسترسی حسابداری فروشگاه ندارید' ], 403 );
        }
        return null;
    }

    public static function shop_acct_meta( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        return new WP_REST_Response( [
            'success'  => true,
            'meta'     => Arag_Shop_Accounting::meta(),
            'portal'   => Arag_Erp::portal_settings(),
            'can_post' => Arag_Erp::erp_can_post(),
            'config'   => Arag_Erp::get_config(),
        ] );
    }

    public static function shop_acct_dashboard( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        return new WP_REST_Response( [ 'success' => true, 'data' => Arag_Shop_Accounting::dashboard() ] );
    }

    public static function shop_acct_documents( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        $state = sanitize_text_field( $req->get_param( 'state' ) ?? '' );
        $limit = min( 200, max( 1, (int) ( $req->get_param( 'limit' ) ?? 80 ) ) );
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Shop_Accounting::list_documents( $limit, $state ),
            'meta'    => Arag_Shop_Accounting::meta(),
        ] );
    }

    public static function shop_acct_document_detail( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        $row = Arag_Shop_Accounting::event_detail( (int) $req->get_param( 'id' ) );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'سند یافت نشد' ], 404 );
        }
        return new WP_REST_Response( [ 'success' => true, 'data' => $row ] );
    }

    public static function shop_acct_ledger( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        $from  = $req->get_param( 'date_from' ) ?: null;
        $to    = $req->get_param( 'date_to' ) ?: null;
        $limit = min( 500, max( 1, (int) ( $req->get_param( 'limit' ) ?? 200 ) ) );
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Shop_Accounting::ledger( $from ? sanitize_text_field( $from ) : null, $to ? sanitize_text_field( $to ) : null, $limit ),
            'meta'    => Arag_Shop_Accounting::meta(),
        ] );
    }

    public static function shop_acct_trial_balance( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        $from = $req->get_param( 'date_from' ) ?: null;
        $to   = $req->get_param( 'date_to' ) ?: null;
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Shop_Accounting::trial_balance(
                $from ? sanitize_text_field( $from ) : null,
                $to ? sanitize_text_field( $to ) : null
            ),
        ] );
    }

    public static function shop_acct_income_statement( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        $from = $req->get_param( 'date_from' ) ?: null;
        $to   = $req->get_param( 'date_to' ) ?: null;
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Shop_Accounting::income_statement(
                $from ? sanitize_text_field( $from ) : null,
                $to ? sanitize_text_field( $to ) : null
            ),
        ] );
    }

    public static function shop_acct_chart( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Shop_Accounting::chart_accounts(),
            'meta'    => Arag_Shop_Accounting::meta(),
        ] );
    }

    public static function shop_acct_pending( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::shop_acct_deny() ) return $d;
        return new WP_REST_Response( [
            'success'  => true,
            'data'     => Arag_Erp::pending_accounting_queue( 50 ),
            'can_post' => Arag_Erp::erp_can_post(),
            'meta'     => Arag_Shop_Accounting::meta(),
        ] );
    }

    public static function shop_acct_post( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'مجوز صدور سند ندارید' ], 403 );
        }
        $res = Arag_Erp::post_order_by_accountant( (int) $req->get_param( 'order_id' ) );
        return new WP_REST_Response( $res, ! empty( $res['success'] ) ? 200 : 400 );
    }

    private static function _shop_abc(): void {
        require_once ACC_PATH . 'includes/helpers/arag-activity-cost.php';
    }

    public static function shop_acct_activities( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        self::_shop_abc();
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Activity_Cost::list_activities( false ),
            'roles'   => Arag_Activity_Cost::role_labels(),
        ] );
    }

    public static function shop_acct_cost_graph( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        self::_shop_abc();
        $data = Arag_Activity_Cost::cost_graph( [
            'date_from' => $req->get_param( 'date_from' ) ?: date( 'Y-m-01' ),
            'date_to'   => $req->get_param( 'date_to' ) ?: date( 'Y-m-d' ),
            'order_id'  => (int) ( $req->get_param( 'order_id' ) ?: 0 ),
        ] );
        return new WP_REST_Response( [ 'success' => true, 'data' => $data ] );
    }

    public static function shop_acct_activity_cost( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        self::_shop_abc();
        $order = Arag_Erp::get_order( (int) $req->get_param( 'order_id' ) );
        if ( ! $order ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'سفارش یافت نشد' ], 404 );
        }
        return new WP_REST_Response( [ 'success' => true, 'data' => Arag_Activity_Cost::allocate( $order ) ] );
    }

    public static function shop_acct_allocate( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() && ! Arag_Erp::erp_can_view() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'دسترسی ندارید' ], 403 );
        }
        self::_shop_abc();
        $oid = (int) $req->get_param( 'order_id' );
        $order = Arag_Erp::get_order( $oid );
        if ( ! $order ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'سفارش یافت نشد' ], 404 );
        }
        $alloc = Arag_Activity_Cost::allocate( $order );
        Arag_Activity_Cost::persist( $oid, $alloc );
        return new WP_REST_Response( [
            'success' => true,
            'message' => 'تخصیص فعالیت فروش ذخیره شد',
            'data'    => $alloc,
        ] );
    }

    public static function shop_acct_get_crew( WP_REST_Request $req ): WP_REST_Response {
        if ( $d = self::deny() ) return $d;
        self::_shop_abc();
        $oid = (int) $req->get_param( 'order_id' );
        return new WP_REST_Response( [
            'success' => true,
            'data'    => Arag_Activity_Cost::get_crew( $oid ),
            'roles'   => Arag_Activity_Cost::role_labels(),
        ] );
    }

    public static function shop_acct_save_crew( WP_REST_Request $req ): WP_REST_Response {
        if ( ! Arag_Erp::erp_can_post() ) {
            return new WP_REST_Response( [ 'success' => false, 'message' => 'مجوز ندارید' ], 403 );
        }
        self::_shop_abc();
        $oid = (int) $req->get_param( 'order_id' );
        $body = $req->get_json_params() ?: [];
        $members = $body['crew'] ?? $body['members'] ?? [];
        return new WP_REST_Response( Arag_Activity_Cost::save_crew( $oid, is_array( $members ) ? $members : [] ) );
    }
}
