<?php
/*
Plugin Name: ACC Engine
Description: ERP SPA Engine
Version: 1.0
*/

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

define( 'ACC_PATH', plugin_dir_path( __FILE__ ) );
define( 'ACC_URL', plugin_dir_url( __FILE__ ) );

require_once ACC_PATH . 'includes/install.php';
require_once ACC_PATH . 'includes/helpers/InventoryIntegration.php';
require_once ACC_PATH . 'includes/helpers/acl-scope-registry.php';
require_once ACC_PATH . 'includes/helpers/acl-scope-enforce.php';
require_once ACC_PATH . 'includes/helpers/acl-functions.php';

class ACC_Engine {

    /**
     * Whitelist of classes allowed to be used as REST callbacks from the DB routes table.
     * Only add trusted controller classes here.
     */
    private static array $allowed_db_callback_classes = [
        'ACC_AuthController',
        'ACC_DashboardController',
        'ACC_SmartFlow_Controller',
        'ACC_Runtime_REST_API_Full',
        'ACC_Runtime_Workflow_API',
        'ACC_Accounting_Controller',
        'ACC_Sales_Controller',
        'ACC_Purchase_Controller',
        'ACC_Payroll_Controller',
        'CPM_Controller',
        'CPM_Assignments_Controller',
        'CPM_Resources_Controller',
        'CPM_Dependencies_Controller',
        'CPM_WBS_Controller',
        'PC_Controller',
        'CRM_Controller',
        'GIS_Controller',
        'Inventory_Controller',
        'UserPrefs_Controller',
        'ACL_Controller',
        'GIS_Locations_Controller',
        'HR_Controller',
        'Workflow_Controller',
        'Shipping_Controller',
        'Assets_Controller',
        'Commission_Controller',
        'Contract_Controller',
        'UnitSales_Controller',
        'Treasury_Controller',
        'Permits_Controller',
        'WP_Products_Controller',
        'WP_Orders_Controller',
        'Chat_Controller',
        'SR_Controller',
        'Eqtesad_Melk_Controller',
    ];

    public function __construct() {
        add_action( 'plugins_loaded', [ $this, 'load_core' ] );
        add_action( 'plugins_loaded', [ $this, 'load_modules' ] );
        add_action( 'init', [ $this, 'register_routes' ] );
        add_action( 'rest_api_init', [ $this, 'register_api_from_db' ] );
        add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
        add_filter( 'script_loader_tag', [ $this, 'add_module_type' ], 10, 3 );

        // حذف Google Fonts در SPA (سرور دسترسی به اینترنت ندارد → timeout)
        add_action( 'wp_print_styles', [ $this, 'remove_google_fonts' ], 100 );
    }

    public function remove_google_fonts(): void {
        if ( ! $this->is_spa_request() ) return;
        global $wp_styles;
        if ( ! isset( $wp_styles->registered ) ) return;
        foreach ( $wp_styles->registered as $handle => $style ) {
            if ( isset( $style->src ) && strpos( $style->src, 'fonts.googleapis.com' ) !== false ) {
                wp_dequeue_style( $handle );
                wp_deregister_style( $handle );
            }
        }
    }

    public function register_api_from_db(): void {
        global $wpdb;

        $table  = $wpdb->prefix . 'erp_api_routes';
        $routes = $wpdb->get_results( "SELECT * FROM {$table}" );

        if ( ! $routes ) {
            return;
        }

        foreach ( $routes as $row ) {
            $callback = $this->resolve_safe_callback( $row->callback );

            if ( $callback === null ) {
                continue;
            }

            $permission = ! empty( $row->permission_callback ) ? $row->permission_callback : 'acc_jwt_check_permission';

            register_rest_route( 'acc/v1', $row->route, [
                'methods'             => $row->method,
                'callback'            => $callback,
                'permission_callback' => $permission,
            ] );
        }
    }

    /**
     * Validates a callback string from the DB against the allowed whitelist.
     * Returns a callable or null if not allowed.
     */
    private function resolve_safe_callback( string $raw ): callable|null {
        if ( str_contains( $raw, '::' ) ) {
            [ $class, $method ] = explode( '::', $raw, 2 );

            if ( ! in_array( $class, self::$allowed_db_callback_classes, true ) ) {
                return null;
            }

            if ( ! method_exists( $class, $method ) ) {
                return null;
            }

            return [ $class, $method ];
        }

        if ( function_exists( $raw ) ) {
            return $raw;
        }

        return null;
    }

    /* -------------------------------------------------------
     * Core
     * ------------------------------------------------------- */
    public function load_core(): void {
        require_once ACC_PATH . 'includes/controllers/class-acc-auth-controller.php';
        require_once ACC_PATH . 'includes/controllers/class-acc-dashboard-controller.php';
        require_once ACC_PATH . 'includes/controllers/class-acc-smartflow-controller.php';
        require_once ACC_PATH . 'includes/helpers/acc-event-engine.php';
        require_once ACC_PATH . 'includes/controllers/ACC_Accounting_Controller.php';
        add_action( 'rest_api_init', [ 'ACC_Accounting_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/ACC_Sales_Controller.php';
        add_action( 'rest_api_init', [ 'ACC_Sales_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/ACC_Purchase_Controller.php';
        add_action( 'rest_api_init', [ 'ACC_Purchase_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/ACC_Payroll_Controller.php';
        add_action( 'rest_api_init', [ 'ACC_Payroll_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/TileProxy_Controller.php';
        add_action( 'rest_api_init', [ 'TileProxy_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/CRM_Controller.php';
        add_action( 'rest_api_init', [ 'CRM_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/CPM_Calculator.php';
        require_once ACC_PATH . 'includes/controllers/PC_Controller.php';
        add_action( 'rest_api_init', [ 'PC_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/GIS_Controller.php';
        add_action( 'rest_api_init', [ 'GIS_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Eqtesad_Melk_Controller.php';
        add_action( 'rest_api_init', [ 'Eqtesad_Melk_Controller', 'register_routes' ] );
        // cron شبانه: بازسازی انبار آمار بلوک‌ها (داشبورد املاک)
        add_action( 'acc_gis_rebuild_block_stats', [ 'GIS_Controller', 'rebuild_block_stats' ] );

        require_once ACC_PATH . 'includes/controllers/Inventory_Controller.php';
        add_action( 'rest_api_init', [ 'Inventory_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/UserPrefs_Controller.php';
        add_action( 'rest_api_init', [ 'UserPrefs_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/ACL_Controller.php';
        add_action( 'rest_api_init', [ 'ACL_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/GIS_Locations_Controller.php';
        add_action( 'rest_api_init', [ 'GIS_Locations_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/HR_Controller.php';
        add_action( 'rest_api_init', [ 'HR_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Workflow_Controller.php';
        add_action( 'rest_api_init', [ 'Workflow_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Shipping_Controller.php';
        add_action( 'rest_api_init', [ 'Shipping_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Assets_Controller.php';
        add_action( 'rest_api_init', [ 'Assets_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Commission_Controller.php';
        add_action( 'rest_api_init', [ 'Commission_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Contract_Controller.php';
        add_action( 'rest_api_init', [ 'Contract_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/UnitSales_Controller.php';
        add_action( 'rest_api_init', [ 'UnitSales_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Treasury_Controller.php';
        add_action( 'rest_api_init', [ 'Treasury_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Permits_Controller.php';
        add_action( 'rest_api_init', [ 'Permits_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/WP_Products_Controller.php';
        add_action( 'rest_api_init', [ 'WP_Products_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/WP_Orders_Controller.php';
        add_action( 'rest_api_init', [ 'WP_Orders_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Projects_Controller.php';
        add_action( 'rest_api_init', [ 'Projects_Controller', 'register_routes' ] );
        Projects_Controller::install();

        require_once ACC_PATH . 'includes/controllers/Chat_Controller.php';
        add_action( 'rest_api_init', [ 'Chat_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/SR_Controller.php';
        add_action( 'rest_api_init', [ 'SR_Controller', 'register_routes' ] );
        add_action( 'acc_svc_pm_daily', [ 'SR_Controller', 'cron_pm_reminders' ] );

        require_once ACC_PATH . 'includes/controllers/SR_Supplier_Controller.php';
        add_action( 'rest_api_init', [ 'SR_Supplier_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/SR_Talent_Controller.php';
        add_action( 'rest_api_init', [ 'SR_Talent_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/SR_Accounting_Controller.php';
        add_action( 'rest_api_init', [ 'SR_Accounting_Controller', 'register_routes' ] );

        require_once ACC_PATH . 'includes/controllers/Public_Auth_Controller.php';
        add_action( 'rest_api_init', [ 'Public_Auth_Controller', 'register_routes' ] );

        $this->ensure_menus();

        require_once ACC_PATH . 'includes/controllers/CPM_Assignments_Controller.php';
        require_once ACC_PATH . 'includes/controllers/CPM_Controller.php';
        require_once ACC_PATH . 'includes/controllers/CPM_Dependencies_Controller.php';
        require_once ACC_PATH . 'includes/controllers/CPM_Resources_Controller.php';
        require_once ACC_PATH . 'includes/controllers/CPM_WBS_Controller.php';

        require_once ACC_PATH . 'includes/runtime/ACC_Runtime_Industrial_REST_API_Full.php';
        require_once ACC_PATH . 'includes/runtime/ACC_Runtime_Query_Engine.php';
        require_once ACC_PATH . 'includes/runtime/ACC_Runtime_Permission_Engine.php';
        require_once ACC_PATH . 'includes/runtime/ACC_Runtime_Workflow_API.php';

        ACC_Runtime_REST_API_Full::init();
    }

    /* -------------------------------------------------------
     * Auto-insert missing menus (for existing installations)
     * ------------------------------------------------------- */
    public function ensure_menus(): void {
        global $wpdb;
        $table = $wpdb->prefix . 'acl_menus';

        // بررسی وجود جدول
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table}'" ) !== $table ) return;

        $new_menus = [
            [ 'workflow',   '', '🔄 Workflow پروژه‌ها', '🔄', 'workflow',   'cpm.view', 55 ],
            [ 'wpproducts',  '', '🛍️ محصولات فروشگاه',  '🛍️', 'wpproducts',  '',  25 ],
            [ 'chat',        '', '💬 چت و پشتیبانی',    '💬', 'chat',        '',  15 ],
            [ 'service',     '', '🔧 خدمات میدانی',     '🔧', 'service',     'service.view', 16 ],
            [ 'realestate',       '', '🏘️ داشبورد املاک',    '🏘️', 'realestate',       '',  20 ],
            [ 'projects-manager', '', '📁 مدیریت پروژه‌ها', '📁', 'projects-manager', '',  30 ],
        ];

        foreach ( $new_menus as $m ) {
            $exists = $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$table} WHERE menu_key = %s", $m[0]
            ) );
            if ( ! $exists ) {
                $wpdb->insert( $table, [
                    'menu_key'            => $m[0],
                    'parent_key'          => $m[1],
                    'title'               => $m[2],
                    'icon'                => $m[3],
                    'route'               => $m[4],
                    'required_permission' => $m[5],
                    'sort_order'          => $m[6],
                ] );
            }
        }
    }

    /* -------------------------------------------------------
     * Modules
     * ------------------------------------------------------- */
    public function load_modules(): void {
        require_once ACC_PATH . 'modules/trrc/rest.php';
        require_once ACC_PATH . 'modules/users/rest.php';
    }

    /* -------------------------------------------------------
     * SPA Route
     * ------------------------------------------------------- */
    public function register_routes(): void {
        add_rewrite_rule( '^app/?$', 'index.php?acc_spa=1', 'top' );
        add_rewrite_tag( '%acc_spa%', '1' );
    }

    /* -------------------------------------------------------
     * Helpers
     * ------------------------------------------------------- */
    private function is_spa_request(): bool {
        return (bool) get_query_var( 'acc_spa' );
    }

    private function get_front_boot_config(): array {
        return [
            'api'       => rest_url( 'acc/v1' ),
            'pluginUrl' => ACC_URL,
        ];
    }

    /* -------------------------------------------------------
     * Module Script Helper
     * ------------------------------------------------------- */
    private function register_module_script(
        string $handle,
        string $src,
        array $deps = [],
        string $ver = '1.0',
        bool $in_footer = true
    ): void {
        wp_register_script( $handle, $src, $deps, $ver, $in_footer );
        wp_script_add_data( $handle, 'type', 'module' );
    }

    /* -------------------------------------------------------
     * Front Assets
     * ------------------------------------------------------- */
    public function enqueue_assets(): void {

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

        wp_enqueue_script( 'wp-polyfill' );

        $front_boot = $this->get_front_boot_config();

        // ── Bundle شده با Vite ──────────────────────────────────
        $dist_js = ACC_PATH . 'assets/dist/acc-app.js';
        $dist_ver = file_exists( $dist_js ) ? filemtime( $dist_js ) : '1.0';

        $this->register_module_script(
            'acc-app-bootstrap',
            ACC_URL . 'assets/dist/acc-app.js',
            [],
            $dist_ver,
            true
        );

        wp_enqueue_script( 'acc-app-bootstrap' );

        wp_localize_script( 'acc-app-bootstrap', 'ACC_CONFIG', $front_boot );

        $rest_base = esc_url_raw( rest_url() );

        wp_localize_script(
            'acc-app-bootstrap',
            'ACC_APP_BOOT',
            [
                'restBase'      => $rest_base,
                'api'           => $rest_base,
                'nonce'         => wp_create_nonce( 'wp_rest' ),
                'loginViewVer'  => $dist_ver,
            ]
        );

        // ── Leaflet (local copy — no CDN needed) ─────────────────
        wp_enqueue_style(
            'leaflet-css',
            ACC_URL . 'assets/vendor/leaflet/leaflet.css',
            [],
            '1.9.4'
        );
        wp_enqueue_script(
            'leaflet-js',
            ACC_URL . 'assets/vendor/leaflet/leaflet.js',
            [],
            '1.9.4',
            false  // در header لود شود — قبل از module scripts
        );

        wp_enqueue_style(
            'all-min-css',
            ACC_URL . 'assets/css/all.min.css',
            [],
            '1.0'
        );

        wp_enqueue_style(
            'tabulator-css',
            ACC_URL . 'tabulator-master/dist/css/tabulator.min.css',
            [],
            '6.2'
        );

        wp_enqueue_style(
            'acc-style',
            ACC_URL . 'assets/css/app.css',
            [ 'tabulator-css' ],
            '1.0'
        );

        // صفحه landing عمومی
        wp_enqueue_style(
            'acc-landing',
            ACC_URL . 'assets/css/base/landing.css',
            [],
            '1.0'
        );

        $config_path = ACC_PATH . 'config/acc-assets.php';

        if ( ! file_exists( $config_path ) ) {
            return;
        }

        $assets = require $config_path;

        if ( empty( $assets['enabled'] ) ) {
            return;
        }

        if ( ! empty( $assets['styles'] ) ) {
            foreach ( $assets['styles'] as $style ) {
                if ( empty( $style['handle'] ) || empty( $style['src'] ) ) {
                    continue;
                }
                wp_enqueue_style(
                    $style['handle'],
                    ACC_URL . ltrim( $style['src'], '/' ),
                    $style['deps'] ?? [],
                    $style['ver'] ?? '1.0'
                );
            }
        }

        if ( ! empty( $assets['scripts'] ) ) {
            foreach ( $assets['scripts'] as $script ) {
                if ( empty( $script['handle'] ) || empty( $script['src'] ) ) {
                    continue;
                }
                $handle    = $script['handle'];
                $src       = ACC_URL . ltrim( $script['src'], '/' );
                $deps      = $script['deps'] ?? [];
                $ver       = $script['ver'] ?? '1.0';
                $in_footer = $script['in_footer'] ?? true;

                wp_register_script( $handle, $src, $deps, $ver, $in_footer );

                if ( ( $script['load'] ?? '' ) === 'module' ) {
                    wp_script_add_data( $handle, 'type', 'module' );
                }

                wp_enqueue_script( $handle );
            }
        }
    }

    /* -------------------------------------------------------
     * Script Module Fix
     * ------------------------------------------------------- */
    public function add_module_type( $tag, $handle, $src ) {

        $modules = [
            'acc-app-bootstrap',
            'acc-smartflow',
            'trrc',
        ];

        if ( in_array( $handle, $modules, true ) ) {
            $tag = str_replace( '<script ', '<script type="module" ', $tag );
        }

        return $tag;
    }
}

new ACC_Engine();

add_filter( 'template_include', function ( $template ) {
    if ( get_query_var( 'acc_spa' ) ) {
        return ACC_PATH . 'templates/spa.php';
    }
    return $template;
} );
