<?php
/**
 * svc-accounting.php — حسابداری و بهای تمام‌شده پورتال خدمات HVAC
 * اتصال به موتور ابعاد و صدور سند ERP
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class Svc_Accounting {

    /** حساب‌های GL (هم‌تراز accounting_engine_v2 + توسعه خدمات) */
    public const GL = [
        'bank'              => 14,
        'ar'                => 21,
        'inventory'         => 22,
        'ap'                => 32,
        'payroll_payable'   => 33,
        'vat'               => 35,
        'revenue_goods'     => 51,
        'revenue_service'   => 52,
        'sales_discount'    => 53,
        'cogs'              => 61,
        'payroll_expense'   => 62,
        'general_expense'   => 63,
        'svc_cogs'          => 65,
        'svc_reward_exp'    => 66,
        'svc_tech_fee'      => 67,
        'svc_senior_fee'    => 68,
        'svc_overhead'      => 69,
        'svc_supplier_ap'   => 70,
    ];

    public static function config_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'svc_acc_config';
    }

    public static function splits_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'svc_acc_splits';
    }

    public static function journal_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'svc_acc_journal';
    }

    /** تنظیمات پیش‌فرض سهم‌ها (درصد از مبنا) */
    public static function default_config(): array {
        return [
            'tech_service_pct'       => 15.0,
            'tech_parts_pct'         => 2.0,
            'senior_service_pct'     => 5.0,
            'senior_team_override_pct' => 3.0,
            'supplier_margin_pct'    => 18.0,
            'discount_company_pct'   => 100.0,
            'reward_expense_per_point' => 50.0,
            'overhead_energy_pct'    => 2.0,
            'overhead_repair_pct'    => 1.5,
            'parts_cogs_pct'         => 65.0,
            'auto_post'              => false,
            'use_dimensions'         => true,
        ];
    }

    /** هویت شعبه/دفتر خدمات (برای تفکیک چند پورتال) */
    public static function default_portal(): array {
        return [
            'office_code'      => 'HVAC-01',
            'office_name'      => 'خدمات سردخانه و چیلر',
            'subsystem_label'  => 'پورتال خدمات HVAC',
            'ledger_tag'       => 'SERVICE',
        ];
    }

    public static function portal_settings(): array {
        $saved = get_option( 'svc_portal_office', [] );
        if ( ! is_array( $saved ) ) {
            $saved = [];
        }
        return array_merge( self::default_portal(), $saved );
    }

    public static function save_portal_settings( array $data ): bool {
        $base = self::default_portal();
        $out  = [];
        foreach ( array_keys( $base ) as $k ) {
            if ( isset( $data[ $k ] ) ) {
                $out[ $k ] = sanitize_text_field( (string) $data[ $k ] );
            }
        }
        return update_option( 'svc_portal_office', array_merge( $base, $out ), false );
    }

    private static function _desc_tag( string $desc ): string {
        $p = self::portal_settings();
        $tag = '[' . ( $p['ledger_tag'] ?? 'SERVICE' ) . '|' . ( $p['office_name'] ?? 'خدمات' ) . ']';
        return $tag . ' ' . $desc;
    }

    private static function _enrich_payload( array $payload ): array {
        $portal = self::portal_settings();
        $payload['source_module']       = 'service_portal';
        $payload['service_office_code'] = $portal['office_code'];
        $payload['service_office_name'] = $portal['office_name'];
        $payload['subsystem_label']     = $portal['subsystem_label'];
        $payload['ledger_tag']          = $portal['ledger_tag'];
        return $payload;
    }

    public static function get_config( ?string $service_type = null ): array {
        global $wpdb;
        $t = self::config_table();
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t ) ) !== $t ) {
            return self::default_config();
        }
        $base = self::default_config();
        $row = $wpdb->get_row(
            "SELECT payload FROM {$t} WHERE service_type IS NULL OR service_type = '' ORDER BY id ASC LIMIT 1",
            ARRAY_A
        );
        if ( $row ) {
            $base = array_merge( $base, json_decode( $row['payload'] ?? '{}', true ) ?: [] );
        }
        if ( $service_type ) {
            $spec = $wpdb->get_var( $wpdb->prepare(
                "SELECT payload FROM {$t} WHERE service_type = %s LIMIT 1", $service_type
            ) );
            if ( $spec ) {
                $base = array_merge( $base, json_decode( $spec, true ) ?: [] );
            }
        }
        return $base;
    }

    public static function save_config( array $payload, ?string $service_type = null ): bool {
        global $wpdb;
        $t = self::config_table();
        $json = wp_json_encode( $payload, JSON_UNESCAPED_UNICODE );
        $existing = $wpdb->get_var( $service_type
            ? $wpdb->prepare( "SELECT id FROM {$t} WHERE service_type = %s", $service_type )
            : "SELECT id FROM {$t} WHERE service_type IS NULL OR service_type = '' LIMIT 1"
        );
        if ( $existing ) {
            return (bool) $wpdb->update( $t, [
                'payload'    => $json,
                'updated_at' => current_time( 'mysql' ),
            ], [ 'id' => (int) $existing ] );
        }
        return (bool) $wpdb->insert( $t, [
            'service_type' => $service_type,
            'payload'      => $json,
            'updated_at'   => current_time( 'mysql' ),
        ] );
    }

    /**
     * محاسبه تفکیک بهای تمام‌شده از گزارش نهایی
     */
    public static function calculate_splits( array $report, ?array $request = null ): array {
        $req = $request ?: [];
        if ( empty( $req ) && ! empty( $report['request_id'] ) ) {
            global $wpdb;
            $req = $wpdb->get_row( $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}svc_requests WHERE id = %d", (int) $report['request_id']
            ), ARRAY_A ) ?: [];
        }

        $svc_type = $req['service_type'] ?? 'repair';
        $cfg      = self::get_config( $svc_type );

        $services  = (float) ( $report['subtotal_services'] ?? 0 );
        $parts     = (float) ( $report['subtotal_parts'] ?? 0 );
        $materials = (float) ( $report['subtotal_materials'] ?? 0 );
        $extra     = (float) ( $report['subtotal_extra'] ?? 0 );
        $discount  = (float) ( $report['discount'] ?? 0 );
        $tax       = (float) ( $report['tax'] ?? 0 );
        $total     = (float) ( $report['total'] ?? 0 );

        $gross = $services + $parts + $materials + $extra;
        $disc_svc = $gross > 0 ? $discount * ( $services / $gross ) : 0;
        $disc_parts = $gross > 0 ? $discount * ( $parts / $gross ) : 0;
        $disc_other = $discount - $disc_svc - $disc_parts;

        $net_services = max( 0, $services - $disc_svc );
        $net_parts    = max( 0, $parts - $disc_parts );
        $net_materials = max( 0, $materials );
        $net_extra    = max( 0, $extra - $disc_other );

        $tech_id   = (int) ( $report['technician_id'] ?? $req['assigned_technician_id'] ?? 0 );
        $senior_id = 0;
        if ( $tech_id && file_exists( ACC_PATH . 'includes/helpers/svc-teams.php' ) ) {
            require_once ACC_PATH . 'includes/helpers/svc-teams.php';
            $senior_id = (int) ( Svc_Teams::senior_of_technician( $tech_id ) ?: 0 );
        }

        $tech_fee   = round( $net_services * (float) $cfg['tech_service_pct'] / 100 )
                    + round( $net_parts * (float) $cfg['tech_parts_pct'] / 100 );
        $senior_fee = round( $net_services * (float) $cfg['senior_service_pct'] / 100 );
        if ( $senior_id ) {
            $senior_fee += round( $total * (float) $cfg['senior_team_override_pct'] / 100 );
        }

        $parts_cogs = round( $net_parts * (float) $cfg['parts_cogs_pct'] / 100 );
        $supplier_cost = max( 0, $net_parts - $parts_cogs );
        $discount_expense = round( $discount * (float) $cfg['discount_company_pct'] / 100 );
        $overhead_energy = round( $total * (float) $cfg['overhead_energy_pct'] / 100 );
        $overhead_repair = round( $total * (float) $cfg['overhead_repair_pct'] / 100 );
        $overhead_total  = $overhead_energy + $overhead_repair;

        $direct_cost = $parts_cogs + $supplier_cost + $tech_fee + $senior_fee + $discount_expense + $overhead_total;
        $gross_margin = max( 0, $total - $tax - $direct_cost );

        $customer_phone = $report['phone'] ?? $req['phone'] ?? '';
        $customer_name  = $report['customer_name'] ?? $req['customer_name'] ?? '';

        return [
            'service_type'      => $svc_type,
            'config'            => $cfg,
            'amounts'           => [
                'services'        => $services,
                'parts'           => $parts,
                'materials'       => $materials,
                'extra'           => $extra,
                'discount'        => $discount,
                'tax'             => $tax,
                'total'           => $total,
                'net_services'    => $net_services,
                'net_parts'       => $net_parts,
                'net_materials'   => $net_materials,
                'net_extra'       => $net_extra,
            ],
            'costs'             => [
                'tech_fee'          => $tech_fee,
                'senior_fee'        => $senior_fee,
                'parts_cogs'        => $parts_cogs,
                'supplier_cost'     => $supplier_cost,
                'discount_expense'  => $discount_expense,
                'overhead_energy'   => $overhead_energy,
                'overhead_repair'   => $overhead_repair,
                'overhead_total'    => $overhead_total,
                'direct_cost'       => $direct_cost,
                'gross_margin'      => $gross_margin,
            ],
            'entities'          => [
                'customer_phone' => $customer_phone,
                'customer_name'  => $customer_name,
                'technician_id'  => $tech_id,
                'senior_id'      => $senior_id,
                'report_id'      => (int) ( $report['id'] ?? 0 ),
                'request_id'     => (int) ( $report['request_id'] ?? 0 ),
            ],
        ];
    }

    /**
     * آماده‌سازی حسابداری هنگام نهایی‌سازی SRD (رویداد pending — صدور توسط حسابدار)
     */
    public static function on_report_finalized( array $report ): array {
        global $wpdb;
        if ( empty( $report['id'] ) || ( $report['status'] ?? '' ) !== 'final' ) {
            return [ 'success' => false, 'message' => 'گزارش نهایی نیست' ];
        }

        $pre = $wpdb->prefix;
        if ( ! empty( $report['acc_revenue_event_id'] ) ) {
            $state = (string) $wpdb->get_var( $wpdb->prepare(
                "SELECT workflow_state FROM {$pre}ai_acc_events WHERE id = %d",
                (int) $report['acc_revenue_event_id']
            ) );
            if ( $state === 'posted' ) {
                return [ 'success' => true, 'message' => 'قبلاً ثبت شده', 'skipped' => true ];
            }
            if ( $state === 'pending' || $state === 'failed' ) {
                return [
                    'success'  => true,
                    'pending'  => true,
                    'event_id' => (int) $report['acc_revenue_event_id'],
                    'message'  => 'در صف صدور حسابدار — رویداد #' . (int) $report['acc_revenue_event_id'],
                ];
            }
        }

        $splits = self::calculate_splits( $report );
        $a      = $splits['amounts'];
        $c      = $splits['costs'];

        $payload = self::_enrich_payload( [
            'report_id'       => (int) $report['id'],
            'tracking_code'   => $report['tracking_code'] ?? '',
            'customer_name'   => $splits['entities']['customer_name'],
            'customer_phone'  => $splits['entities']['customer_phone'],
            'technician_id'   => $splits['entities']['technician_id'],
            'senior_id'       => $splits['entities']['senior_id'],
            'service_type'    => $splits['service_type'],
            'net_services'    => $a['net_services'],
            'net_parts'       => $a['net_parts'],
            'net_materials'   => $a['net_materials'],
            'net_extra'       => $a['net_extra'],
            'tax_amount'      => $a['tax'],
            'discount'        => $a['discount'],
            'total_amount'    => $a['total'],
            'tech_fee'        => $c['tech_fee'],
            'senior_fee'      => $c['senior_fee'],
            'parts_cogs'      => $c['parts_cogs'],
            'supplier_cost'   => $c['supplier_cost'],
            'discount_expense'=> $c['discount_expense'],
            'overhead_energy' => $c['overhead_energy'],
            'overhead_repair' => $c['overhead_repair'],
            'dimensions'      => self::_resolve_dimensions_for_splits( $splits ),
            'manual_entries'  => [ 'pairs' => self::_build_finalize_pairs( $a, $c, $splits ) ],
        ] );

        $dim_id = $payload['dimensions']['customer'] ?? $payload['dimensions']['branch'] ?? null;

        $created = self::_create_event(
            'SERVICE_INVOICE',
            (float) $a['total'],
            $payload,
            'svc_report',
            (int) $report['id'],
            $dim_id,
            'svc_finalize_' . $report['id']
        );
        if ( ! $created['success'] ) {
            return $created;
        }

        $event_id = (int) $created['event_id'];

        /* بهای تمام‌شده فعالیت‌ها + سهم نفرها (حسابداری گراف صنعتی) */
        if ( file_exists( ACC_PATH . 'includes/helpers/svc-activity-cost.php' ) ) {
            require_once ACC_PATH . 'includes/helpers/svc-activity-cost.php';
            $abc = Svc_Activity_Cost::allocate( $report, $splits );
            Svc_Activity_Cost::persist_allocation( (int) $report['id'], $abc );
            $splits['activity_cost'] = [
                'pools'         => $abc['pools'],
                'person_shares' => $abc['person_shares'],
                'lines'         => $abc['lines'],
                'totals'        => $abc['totals'],
            ];
        }

        $wpdb->update( "{$wpdb->prefix}svc_reports", [
            'acc_revenue_event_id' => $event_id,
            'acc_splits_json'      => wp_json_encode( $splits, JSON_UNESCAPED_UNICODE ),
        ], [ 'id' => (int) $report['id'] ] );

        self::_persist_splits( (int) $report['id'], $splits, $event_id );

        self::_journal_log( (int) $report['id'], 'SERVICE_INVOICE', $event_id, $a['total'], $payload, 'pending' );

        $cfg = self::get_config( $splits['service_type'] ?? null );
        if ( ! empty( $cfg['auto_post'] ) ) {
            return self::post_report_by_accountant( (int) $report['id'], (int) get_current_user_id() );
        }

        return [
            'success'  => true,
            'pending'  => true,
            'event_id' => $event_id,
            'splits'   => $splits,
            'message'  => 'رویداد #' . $event_id . ' در صف صدور حسابدار ثبت شد',
        ];
    }

    /**
     * صدور سند توسط حسابدار از پورتال خدمات (موتور ERP)
     */
    public static function post_report_by_accountant( int $report_id, int $user_id = 0 ): array {
        global $wpdb;
        $report = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}svc_reports WHERE id = %d AND status = 'final'", $report_id
        ), ARRAY_A );
        if ( ! $report ) {
            return [ 'success' => false, 'message' => 'گزارش نهایی یافت نشد' ];
        }

        if ( empty( $report['acc_revenue_event_id'] ) ) {
            $prep = self::on_report_finalized( $report );
            if ( empty( $prep['event_id'] ) && empty( $report['acc_revenue_event_id'] ) ) {
                $report = $wpdb->get_row( $wpdb->prepare(
                    "SELECT * FROM {$wpdb->prefix}svc_reports WHERE id = %d", $report_id
                ), ARRAY_A );
            }
            if ( empty( $report['acc_revenue_event_id'] ) && ! empty( $prep['event_id'] ) ) {
                $report['acc_revenue_event_id'] = $prep['event_id'];
            }
            if ( empty( $report['acc_revenue_event_id'] ) ) {
                return $prep;
            }
        }

        $event_id = (int) $report['acc_revenue_event_id'];
        $post = self::_erp_post( $event_id );
        if ( ! $post['success'] ) {
            return $post;
        }

        $splits = json_decode( $report['acc_splits_json'] ?? '', true ) ?: self::calculate_splits( $report );
        self::_journal_log( $report_id, 'SERVICE_INVOICE', $event_id, (float) ( $splits['amounts']['total'] ?? $report['total'] ), [], 'posted', $user_id );

        return [
            'success'  => true,
            'event_id' => $event_id,
            'splits'   => $splits,
            'message'  => $post['message'] ?? 'سند صادر شد',
        ];
    }

    /**
     * صدور سند دریافت وجه (پرداخت آنلاین)
     */
    public static function on_payment_received( int $report_id, float $amount, int $payment_id = 0 ): array {
        global $wpdb;
        $report = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}svc_reports WHERE id = %d", $report_id
        ), ARRAY_A );
        if ( ! $report ) {
            return [ 'success' => false, 'message' => 'گزارش یافت نشد' ];
        }

        $payload = self::_enrich_payload( [
            'report_id'     => $report_id,
            'payment_id'    => $payment_id,
            'amount'        => $amount,
            'customer_name' => $report['customer_name'] ?? '',
            'manual_entries' => [ 'pairs' => [
                [ 'dr_gl_id' => self::GL['bank'], 'cr_gl_id' => self::GL['ar'], 'source_field' => 'amount', 'desc' => self::_desc_tag( 'دریافت وجه خدمات' ) ],
            ] ],
        ] );

        $dim_id = self::_resolve_customer_dimension( $report['phone'] ?? '', $report['customer_name'] ?? '' );
        $created = self::_create_event(
            'SERVICE_RECEIPT',
            $amount,
            $payload,
            'svc_payment',
            $payment_id ?: $report_id,
            $dim_id,
            'svc_pay_' . ( $payment_id ?: $report_id ) . '_' . (int) round( $amount )
        );
        if ( ! $created['success'] ) {
            return $created;
        }
        $event_id = (int) $created['event_id'];
        self::_journal_log( $report_id, 'SERVICE_RECEIPT', $event_id, $amount, $payload, 'pending' );

        $cfg = self::get_config();
        if ( ! empty( $cfg['auto_post'] ) ) {
            $post = self::_erp_post( $event_id );
            if ( $post['success'] ) {
                self::_journal_log( $report_id, 'SERVICE_RECEIPT', $event_id, $amount, $payload, 'posted' );
            }
            return $post;
        }
        return [
            'success'  => true,
            'pending'  => true,
            'event_id' => $event_id,
            'message'  => 'دریافت وجه در صف صدور حسابدار',
        ];
    }

    /**
     * سند هزینه تأمین‌کننده هنگام تحویل قطعه
     */
    public static function on_supplier_delivered( array $order ): array {
        $amount = (float) ( $order['quote_price'] ?? 0 );
        if ( $amount <= 0 ) {
            return [ 'success' => true, 'skipped' => true ];
        }
        $payload = self::_enrich_payload( [
            'order_id'    => (int) ( $order['id'] ?? 0 ),
            'supplier_id' => (int) ( $order['supplier_id'] ?? 0 ),
            'part_number' => $order['part_number'] ?? '',
            'amount'      => $amount,
            'manual_entries' => [ 'pairs' => [
                [ 'dr_gl_id' => self::GL['svc_cogs'], 'cr_gl_id' => self::GL['svc_supplier_ap'], 'source_field' => 'amount', 'desc' => self::_desc_tag( 'بهای قطعه تأمین‌کننده' ) ],
            ] ],
        ] );
        $dim_id = self::_resolve_supplier_dimension( (int) ( $order['supplier_id'] ?? 0 ) );
        $created = self::_create_event(
            'SERVICE_SUPPLIER_COST',
            $amount,
            $payload,
            'svc_parts_order',
            (int) ( $order['id'] ?? 0 ),
            $dim_id,
            'svc_sup_del_' . ( $order['id'] ?? 0 )
        );
        if ( ! $created['success'] ) {
            return $created;
        }
        $event_id = (int) $created['event_id'];
        self::_journal_log( (int) ( $order['report_id'] ?? 0 ), 'SERVICE_SUPPLIER_COST', $event_id, $amount, $payload, 'pending' );

        $cfg = self::get_config();
        if ( ! empty( $cfg['auto_post'] ) ) {
            return self::_erp_post( $event_id );
        }
        return [
            'success'  => true,
            'pending'  => true,
            'event_id' => $event_id,
            'message'  => 'هزینه تأمین‌کننده در صف صدور حسابدار',
        ];
    }

    private static function _build_finalize_pairs( array $a, array $c, array $splits = [] ): array {
        $pairs = [];
        $G = self::GL;
        $dims = $splits['dimensions'] ?? ( $splits ? self::_resolve_dimensions_for_splits( $splits ) : [] );

        $with_dim = static function( array $pair, int|string|null $dim_key = null ) use ( $dims ): array {
            if ( is_string( $dim_key ) && ! empty( $dims[ $dim_key ] ) ) {
                $pair['dimension_id'] = (int) $dims[ $dim_key ];
            } elseif ( is_int( $dim_key ) && $dim_key > 0 ) {
                $pair['dimension_id'] = $dim_key;
            }
            return $pair;
        };

        if ( $a['net_services'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['ar'], 'cr_gl_id' => $G['revenue_service'], 'source_field' => 'net_services', 'desc' => self::_desc_tag( 'درآمد خدمات' ) ], 'customer' );
        }
        if ( $a['net_parts'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['ar'], 'cr_gl_id' => $G['revenue_goods'], 'source_field' => 'net_parts', 'desc' => self::_desc_tag( 'درآمد قطعات' ) ], 'customer' );
        }
        if ( $a['net_materials'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['ar'], 'cr_gl_id' => $G['revenue_service'], 'source_field' => 'net_materials', 'desc' => self::_desc_tag( 'درآمد مصالح' ) ], 'customer' );
        }
        if ( $a['net_extra'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['ar'], 'cr_gl_id' => $G['revenue_service'], 'source_field' => 'net_extra', 'desc' => self::_desc_tag( 'سایر درآمدها' ) ], 'customer' );
        }
        if ( $a['tax'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['ar'], 'cr_gl_id' => $G['vat'], 'source_field' => 'tax_amount', 'desc' => self::_desc_tag( 'مالیات خدمات' ) ], 'customer' );
        }
        if ( $a['discount'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['sales_discount'], 'cr_gl_id' => $G['ar'], 'source_field' => 'discount', 'desc' => self::_desc_tag( 'تخفیف فاکتور' ) ], 'customer' );
        }
        if ( $c['parts_cogs'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['cogs'], 'cr_gl_id' => $G['inventory'], 'source_field' => 'parts_cogs', 'desc' => self::_desc_tag( 'بهای تمام‌شده قطعات انبار' ) ], 'service' );
        }
        if ( $c['supplier_cost'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_cogs'], 'cr_gl_id' => $G['svc_supplier_ap'], 'source_field' => 'supplier_cost', 'desc' => self::_desc_tag( 'بهای قطعه تأمین‌کننده' ) ], 'supplier' );
        }
        if ( $c['tech_fee'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_tech_fee'], 'cr_gl_id' => $G['payroll_payable'], 'source_field' => 'tech_fee', 'desc' => self::_desc_tag( 'حق‌الزحمه کارشناس' ) ], 'technician' );
        }
        if ( $c['senior_fee'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_senior_fee'], 'cr_gl_id' => $G['payroll_payable'], 'source_field' => 'senior_fee', 'desc' => self::_desc_tag( 'سهم کارشناس ارشد' ) ], 'senior' );
        }
        if ( $c['discount_expense'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_reward_exp'], 'cr_gl_id' => $G['ar'], 'source_field' => 'discount_expense', 'desc' => self::_desc_tag( 'هزینه تخفیف/پاداش مشتری' ) ], 'customer' );
        }
        if ( $c['overhead_energy'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_overhead'], 'cr_gl_id' => $G['general_expense'], 'source_field' => 'overhead_energy', 'desc' => self::_desc_tag( 'سربار انرژی پورتال' ) ], 'overhead_energy' );
        }
        if ( $c['overhead_repair'] > 0 ) {
            $pairs[] = $with_dim( [ 'dr_gl_id' => $G['svc_overhead'], 'cr_gl_id' => $G['general_expense'], 'source_field' => 'overhead_repair', 'desc' => self::_desc_tag( 'سربار تعمیرگاه/کارگاه' ) ], 'overhead_repair' );
        }
        return $pairs;
    }

    private static function _create_event(
        string $event_type,
        float $amount,
        array $payload,
        string $ref_type,
        int $ref_id,
        ?int $dimension_id,
        string $idempotency_key
    ): array {
        if ( ! class_exists( 'Acc_Event_Engine' ) ) {
            require_once ACC_PATH . 'includes/helpers/acc-event-engine.php';
        }
        return Acc_Event_Engine::create_event( [
            'event_type'      => $event_type,
            'amount'          => $amount,
            'payload'         => $payload,
            'reference_type'  => $ref_type,
            'reference_id'    => $ref_id,
            'dimension_id'    => $dimension_id,
            'idempotency_key' => $idempotency_key,
            'source_module'   => 'service_portal',
        ] );
    }

    /** پست از طریق موتور ERP */
    private static function _erp_post( int $event_id ): array {
        if ( ! class_exists( 'Acc_Event_Engine' ) ) {
            require_once ACC_PATH . 'includes/helpers/acc-event-engine.php';
        }
        return Acc_Event_Engine::post_event( $event_id );
    }

    /** @deprecated از _erp_post استفاده کنید */
    public static function _post_event_php( int $event_id ): array {
        return self::_erp_post( $event_id );
    }

    private static function _persist_splits( int $report_id, array $splits, int $event_id ): void {
        global $wpdb;
        $t = self::splits_table();
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t ) ) !== $t ) return;

        $wpdb->delete( $t, [ 'report_id' => $report_id ] );
        $tech_label = '';
        $senior_label = '';
        if ( ! empty( $splits['entities']['technician_id'] ) ) {
            $tech_label = (string) $wpdb->get_var( $wpdb->prepare(
                "SELECT display_name FROM {$wpdb->users} WHERE ID = %d", (int) $splits['entities']['technician_id']
            ) );
        }
        if ( ! empty( $splits['entities']['senior_id'] ) ) {
            $senior_label = (string) $wpdb->get_var( $wpdb->prepare(
                "SELECT display_name FROM {$wpdb->users} WHERE ID = %d", (int) $splits['entities']['senior_id']
            ) );
        }
        $rows = [
            [ 'customer', 0, $splits['entities']['customer_name'], $splits['amounts']['total'], 0, 0 ],
            [ 'technician', $splits['entities']['technician_id'], $tech_label, 0, $splits['costs']['tech_fee'], $splits['costs']['tech_fee'] ],
            [ 'senior', $splits['entities']['senior_id'], $senior_label, 0, $splits['costs']['senior_fee'], $splits['costs']['senior_fee'] ],
            [ 'company', 0, 'شرکت', $splits['amounts']['total'], $splits['costs']['direct_cost'], $splits['costs']['gross_margin'] ],
        ];

        /* سهم چندنفره از تخصیص ABC (اگر موجود باشد) */
        if ( ! empty( $splits['activity_cost']['person_shares'] ) && is_array( $splits['activity_cost']['person_shares'] ) ) {
            foreach ( $splits['activity_cost']['person_shares'] as $ps ) {
                $pid = (int) ( $ps['person_id'] ?? 0 );
                if ( $pid <= 0 ) continue;
                if ( $pid === (int) $splits['entities']['technician_id'] || $pid === (int) $splits['entities']['senior_id'] ) {
                    continue; /* قبلاً به‌عنوان tech/senior ثبت شده */
                }
                $rows[] = [
                    'crew',
                    $pid,
                    $ps['name'] ?? ( 'نفر #' . $pid ),
                    (float) ( $ps['revenue_share'] ?? 0 ),
                    (float) ( $ps['amount'] ?? 0 ),
                    (float) ( $ps['amount'] ?? 0 ),
                ];
            }
        }

        foreach ( $rows as [ $type, $eid, $label, $rev, $cost, $margin ] ) {
            if ( $type !== 'customer' && ! $eid && $type !== 'company' ) continue;
            $wpdb->insert( $t, [
                'report_id'    => $report_id,
                'entity_type'  => $type,
                'entity_id'    => $eid,
                'entity_label' => $label,
                'revenue_share' => $rev,
                'cost_share'   => $cost,
                'fee_amount'   => $margin,
                'acc_event_id' => $event_id,
            ] );
        }
    }

    private static function _journal_log(
        int $report_id,
        string $event_type,
        int $event_id,
        float $amount,
        array $payload = [],
        string $status = 'posted',
        int $posted_by = 0
    ): void {
        global $wpdb;
        $t = self::journal_table();
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t ) ) !== $t ) {
            return;
        }
        $row = [
            'report_id'    => $report_id ?: null,
            'event_type'   => $event_type,
            'acc_event_id' => $event_id,
            'amount'       => $amount,
            'status'       => $status,
            'payload'      => wp_json_encode( array_merge( $payload, [
                'posted_by' => $posted_by ?: (int) get_current_user_id(),
            ] ), JSON_UNESCAPED_UNICODE ),
        ];
        $existing = $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$t} WHERE acc_event_id = %d AND event_type = %s LIMIT 1",
            $event_id, $event_type
        ) );
        if ( $existing ) {
            $wpdb->update( $t, $row, [ 'id' => (int) $existing ] );
            return;
        }
        $wpdb->insert( $t, $row );
    }

    private static function _resolve_customer_dimension( string $phone, string $name ): ?int {
        if ( ! $phone && ! $name ) return null;
        return self::_ensure_dimension_value( 'PARTY', 'مشتری خدمات', $phone ?: $name, "مشتری HVAC: {$name}" );
    }

    private static function _resolve_personnel_dimension( int $user_id, string $role ): ?int {
        if ( ! $user_id ) return null;
        global $wpdb;
        $name = (string) $wpdb->get_var( $wpdb->prepare(
            "SELECT display_name FROM {$wpdb->users} WHERE ID = %d", $user_id
        ) );
        $dim_name = $role === 'senior' ? 'کارشناس ارشد' : 'کارشناس';
        $label = $name ?: ( $role === 'senior' ? "ارشد #{$user_id}" : "کارشناس #{$user_id}" );
        return self::_ensure_dimension_value( 'PERSONNEL', $dim_name, strtoupper( $role ) . '-' . $user_id, $label );
    }

    private static function _resolve_service_dimension( string $service_type ): ?int {
        if ( ! $service_type ) return null;
        $labels = class_exists( 'SR_Controller' ) ? SR_Controller::$SERVICE_TYPES : [];
        $label  = $labels[ $service_type ] ?? $service_type;
        return self::_ensure_dimension_value( 'SERVICE', 'نوع خدمت', strtoupper( $service_type ), "خدمت: {$label}" );
    }

    private static function _resolve_overhead_dimension( string $code, string $label ): ?int {
        return self::_ensure_dimension_value( 'COST_CENTER', 'سربار پورتال', strtoupper( $code ), $label );
    }

    private static function _resolve_branch_dimension(): ?int {
        $p = self::portal_settings();
        return self::_ensure_dimension_value(
            'BRANCH',
            'شعبه خدمات',
            strtoupper( $p['office_code'] ?? 'HVAC-01' ),
            $p['office_name'] ?? 'خدمات HVAC'
        );
    }

    private static function _resolve_dimensions_for_splits( array $splits ): array {
        $cfg = $splits['config'] ?? self::get_config( $splits['service_type'] ?? null );
        if ( empty( $cfg['use_dimensions'] ) ) {
            return [];
        }
        $e = $splits['entities'] ?? [];
        $dims = [
            'branch'     => self::_resolve_branch_dimension(),
            'customer'   => self::_resolve_customer_dimension( $e['customer_phone'] ?? '', $e['customer_name'] ?? '' ),
            'service'    => self::_resolve_service_dimension( $splits['service_type'] ?? '' ),
            'technician' => self::_resolve_personnel_dimension( (int) ( $e['technician_id'] ?? 0 ), 'tech' ),
            'senior'     => self::_resolve_personnel_dimension( (int) ( $e['senior_id'] ?? 0 ), 'senior' ),
            'overhead_energy' => self::_resolve_overhead_dimension( 'ENERGY', 'سربار انرژی پورتال HVAC' ),
            'overhead_repair' => self::_resolve_overhead_dimension( 'REPAIR', 'سربار تعمیرگاه/کارگاه' ),
        ];
        return array_filter( $dims );
    }

    /** صف صدور سند برای حسابدار پورتال */
    public static function pending_queue(): array {
        global $wpdb;
        $pre = $wpdb->prefix;
        $portal = self::portal_settings();

        $invoices = $wpdb->get_results(
            "SELECT r.id, r.report_no, r.customer_name, r.total, r.finalized_at,
                    r.acc_revenue_event_id AS event_id, e.workflow_state, e.event_type, e.amount
             FROM {$pre}svc_reports r
             LEFT JOIN {$pre}ai_acc_events e ON e.id = r.acc_revenue_event_id
             WHERE r.status = 'final'
               AND (e.workflow_state IS NULL OR e.workflow_state IN ('pending','failed'))
             ORDER BY r.finalized_at DESC
             LIMIT 100",
            ARRAY_A
        ) ?: [];

        $journal = $wpdb->get_results(
            "SELECT j.*, e.workflow_state, e.event_type AS ev_type
             FROM {$pre}svc_acc_journal j
             LEFT JOIN {$pre}ai_acc_events e ON e.id = j.acc_event_id
             WHERE j.status = 'pending' AND j.event_type IN ('SERVICE_RECEIPT','SERVICE_SUPPLIER_COST')
             ORDER BY j.created_at DESC LIMIT 50",
            ARRAY_A
        ) ?: [];

        return [
            'portal'   => $portal,
            'invoices' => array_map( static function( $r ) use ( $portal ) {
                $r['office_name'] = $portal['office_name'];
                $r['office_code'] = $portal['office_code'];
                $r['label'] = 'فاکتور خدمات';
                return $r;
            }, $invoices ),
            'other'    => $journal,
            'counts'   => [
                'invoices' => count( $invoices ),
                'other'    => count( $journal ),
                'total'    => count( $invoices ) + count( $journal ),
            ],
        ];
    }

    private static function _resolve_supplier_dimension( int $user_id ): ?int {
        if ( ! $user_id ) return null;
        global $wpdb;
        $name = (string) $wpdb->get_var( $wpdb->prepare(
            "SELECT display_name FROM {$wpdb->users} WHERE ID = %d", $user_id
        ) );
        return self::_ensure_dimension_value( 'PARTY', 'تأمین‌کننده', 'SUP-' . $user_id, $name ?: "تأمین‌کننده #{$user_id}" );
    }

    private static function _ensure_dimension_value( string $group_code, string $dim_name, string $value_code, string $value_label ): ?int {
        global $wpdb;
        $pre = $wpdb->prefix;
        $vt = $pre . 'ai_acc_dimension_values';
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $vt ) ) !== $vt ) {
            return null;
        }
        $existing = $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$vt} WHERE value_code = %s LIMIT 1", $value_code
        ) );
        if ( $existing ) return (int) $existing;

        $group_id = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$pre}ai_acc_dimension_groups WHERE group_code = %s", $group_code
        ) );
        if ( ! $group_id ) return null;

        $dim_id = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$pre}ai_acc_dimensions WHERE group_id = %d AND dim_name = %s LIMIT 1",
            $group_id, $dim_name
        ) );
        if ( ! $dim_id ) {
            $wpdb->insert( $pre . 'ai_acc_dimensions', [
                'group_id'  => $group_id,
                'dim_code'  => strtoupper( substr( $group_code, 0, 3 ) ) . '-' . wp_generate_password( 4, false ),
                'dim_name'  => $dim_name,
                'data_type' => 'string',
                'is_active' => 1,
            ] );
            $dim_id = (int) $wpdb->insert_id;
        }
        if ( ! $dim_id ) return null;

        $wpdb->insert( $vt, [
            'dim_id'     => $dim_id,
            'value_code' => $value_code,
            'value_name' => $value_label,
            'is_active'  => 1,
        ] );
        return (int) $wpdb->insert_id;
    }

    /** گزارش بهای تمام‌شده تجمیعی */
    public static function cost_report( array $filters = [] ): array {
        global $wpdb;
        $pre = $wpdb->prefix;
        $from = $filters['date_from'] ?? date( 'Y-m-01' );
        $to   = $filters['date_to'] ?? date( 'Y-m-d' );

        $reports = $wpdb->get_results( $wpdb->prepare(
            "SELECT id, tracking_code, customer_name, phone, total, subtotal_services, subtotal_parts,
                    discount, tax, acc_revenue_event_id, acc_splits_json, finalized_at
             FROM {$pre}svc_reports
             WHERE status = 'final' AND finalized_at BETWEEN %s AND %s
             ORDER BY finalized_at DESC LIMIT 200",
            $from . ' 00:00:00', $to . ' 23:59:59'
        ), ARRAY_A ) ?: [];

        $totals = [
            'revenue' => 0, 'discount' => 0, 'tech_fee' => 0, 'senior_fee' => 0,
            'parts_cogs' => 0, 'supplier_cost' => 0, 'overhead' => 0, 'margin' => 0, 'count' => 0,
        ];
        foreach ( $reports as &$r ) {
            $s = json_decode( $r['acc_splits_json'] ?? '{}', true );
            if ( $s ) {
                $r['splits_summary'] = $s['costs'] ?? [];
                $totals['revenue']      += (float) ( $s['amounts']['total'] ?? $r['total'] );
                $totals['discount']     += (float) ( $s['amounts']['discount'] ?? $r['discount'] );
                $totals['tech_fee']     += (float) ( $s['costs']['tech_fee'] ?? 0 );
                $totals['senior_fee']   += (float) ( $s['costs']['senior_fee'] ?? 0 );
                $totals['parts_cogs']   += (float) ( $s['costs']['parts_cogs'] ?? 0 );
                $totals['supplier_cost']+= (float) ( $s['costs']['supplier_cost'] ?? 0 );
                $totals['overhead']     += (float) ( $s['costs']['overhead_total'] ?? 0 );
                $totals['margin']       += (float) ( $s['costs']['gross_margin'] ?? 0 );
            }
            $totals['count']++;
        }
        unset( $r );

        $by_entity = $wpdb->get_results( $wpdb->prepare(
            "SELECT entity_type, entity_id, entity_label,
                    SUM(revenue_share) AS revenue, SUM(cost_share) AS cost, SUM(fee_amount) AS margin
             FROM {$pre}svc_acc_splits s
             INNER JOIN {$pre}svc_reports r ON r.id = s.report_id
             WHERE r.status = 'final' AND r.finalized_at BETWEEN %s AND %s
             GROUP BY entity_type, entity_id, entity_label
             ORDER BY cost DESC LIMIT 100",
            $from . ' 00:00:00', $to . ' 23:59:59'
        ), ARRAY_A ) ?: [];

        return [
            'period'     => [ 'from' => $from, 'to' => $to ],
            'totals'     => $totals,
            'reports'    => $reports,
            'by_entity'  => $by_entity,
        ];
    }
}
