<?php

if(!function_exists('bot_payment_event_log_append')){
    function bot_payment_event_log_append(array $event){
        $root = defined('BOT_ROOT_DIR') ? rtrim((string)BOT_ROOT_DIR, '/') : rtrim(dirname(__DIR__, 2), '/');
        $dir = $root . '/cache';
        if(!is_dir($dir)) @mkdir($dir, 0775, true);
        $path = $dir . '/payment_report_events.json';
        $all = [];
        if(is_file($path)){
            $j = json_decode((string)@file_get_contents($path), true);
            if(is_array($j)) $all = isset($j['events']) && is_array($j['events']) ? $j['events'] : $j;
        }
        $event['logged_at'] = $event['logged_at'] ?? time();
        $event['status'] = $event['status'] ?? 'paid';
        $id = (string)($event['id'] ?? $event['receipt_id'] ?? $event['track_id'] ?? $event['authority'] ?? $event['factor'] ?? ('event_'.time().'_'.count($all)));
        $key = (string)($event['source'] ?? 'payment').':'.$id.':'.($event['user_id'] ?? '').':'.($event['amount'] ?? '').':'.($event['reward_amount'] ?? '');
        $event['event_key'] = $key;
        foreach($all as $old){ if(is_array($old) && (string)($old['event_key'] ?? '') === $key) return true; }
        $all[] = $event;
        if(count($all) > 5000) $all = array_slice($all, -5000);
        $tmp = $path.'.tmp';
        @file_put_contents($tmp, json_encode(['events'=>$all], JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT), LOCK_EX);
        @rename($tmp, $path);
        return true;
    }
}

/**
 * Zibal payment helper for the simple shop.
 * Replaces the previous Zarinpal implementation while keeping bot_zp_* compatibility wrappers.
 * API flow: request -> start/{trackId} -> callback -> verify.
 */

if (!function_exists('bot_zibal_cfg')) {
    function bot_zibal_cfg(){
        $merchant = '';
        if(function_exists('bot_simple_shop_setting')){
            $merchant = trim((string)bot_simple_shop_setting('zibal_merchant_id', ''));
            if($merchant === '') $merchant = trim((string)bot_simple_shop_setting('zarinpal_merchant_id', ''));
        }
        if($merchant === '' && defined('ZIBAL_MERCHANT_ID')) $merchant = trim((string)ZIBAL_MERCHANT_ID);
        if($merchant === '' && defined('ZARINPAL_MERCHANT_ID')) $merchant = trim((string)ZARINPAL_MERCHANT_ID); // legacy config compatibility
        if($merchant === '') $merchant = '6a22c9706d403d333efab345';

        $callback = defined('ZIBAL_CALLBACK_URL') ? ZIBAL_CALLBACK_URL : '';
        if($callback === ''){
            $public = defined('BOT_PUBLIC_BASE_URL') ? rtrim((string)BOT_PUBLIC_BASE_URL, '/') : '';
            if($public !== '') $callback = $public.'/zibal_callback.php';
        }
        if($callback === '' && defined('ZARINPAL_CALLBACK_URL')) $callback = ZARINPAL_CALLBACK_URL; // old installs still work

        return [
            'merchant_id'=>$merchant,
            'api_request'=>'https://gateway.zibal.ir/v1/request',
            'api_verify'=>'https://gateway.zibal.ir/v1/verify',
            'start_base'=>'https://gateway.zibal.ir/start/',
            'callback_url'=>$callback,
        ];
    }
}

if (!function_exists('bot_zibal_curl_json')) {
    function bot_zibal_curl_json($url, array $payload){
        $body = json_encode($payload, JSON_UNESCAPED_UNICODE);
        if(function_exists('curl_init')){
            $ch = curl_init($url);
            curl_setopt_array($ch, [
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $body,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_HTTPHEADER => ['Content-Type: application/json','Accept: application/json'],
                CURLOPT_CONNECTTIMEOUT => 10,
                CURLOPT_TIMEOUT => 25,
                CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
            ]);
            $raw = curl_exec($ch);
            $err = curl_error($ch);
            $errno = curl_errno($ch);
            $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if($raw === false) return ['ok'=>false,'error'=>'curl_'.$errno, 'message'=>$err, 'http'=>$http];
        }else{
            $ctx = stream_context_create(['http'=>[
                'method'=>'POST',
                'header'=>"Content-Type: application/json\r\nAccept: application/json\r\nContent-Length: ".strlen($body)."\r\n",
                'content'=>$body,
                'timeout'=>25,
            ]]);
            $raw = @file_get_contents($url, false, $ctx);
            $http = 0;
            if($raw === false) return ['ok'=>false,'error'=>'http_request_failed'];
        }
        $json = json_decode((string)$raw, true);
        if(!is_array($json)) return ['ok'=>false,'error'=>'bad_json','raw'=>$raw,'http'=>$http ?? 0];
        return ['ok'=>true,'json'=>$json,'http'=>$http ?? 0,'raw'=>$raw];
    }
}

if (!function_exists('bot_zibal_payment_store_path')) { function bot_zibal_payment_store_path(){ return 'cache/zibal_payments.json'; } }
if (!function_exists('bot_zibal_payment_store_read')) {
    function bot_zibal_payment_store_read(){
        $paths = [bot_zibal_payment_store_path(), 'cache/zarinpal_payments.json']; // read old file too, write only zibal file
        $out = [];
        foreach($paths as $f){
            if(!is_file($f)) continue;
            $v = json_decode((string)file_get_contents($f), true);
            if(is_array($v)) $out = array_replace($out, $v);
        }
        return $out;
    }
}
if (!function_exists('bot_zibal_payment_store_write')) {
    function bot_zibal_payment_store_write(array $v){ if(!is_dir('cache')) @mkdir('cache',0755,true); file_put_contents(bot_zibal_payment_store_path(), json_encode($v,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT)); }
}


if (!function_exists('bot_zibal_receipt_html')) {
    function bot_zibal_receipt_html($v){ return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }
}

if (!function_exists('bot_zibal_receipt_format_money')) {
    function bot_zibal_receipt_format_money($amount){
        if(function_exists('bot_simple_format_money')) return bot_simple_format_money((int)$amount);
        return number_format((int)$amount).' ریال';
    }
}

if (!function_exists('bot_zibal_receipt_channel_settings')) {
    function bot_zibal_receipt_channel_settings(){
        if(function_exists('bot_manual_receipt_channel_settings')) return bot_manual_receipt_channel_settings();
        $def = ['enabled'=>'❌غیر فعال','channel_id'=>'','admin_notify_enabled'=>'✅فعال','updated_at'=>time()];
        $path = 'lib/kodam/manual_receipt_channel.json';
        $data = [];
        if(function_exists('bot_data_get_json')) $data = bot_data_get_json($path, $def);
        elseif(is_file($path)) $data = json_decode((string)@file_get_contents($path), true);
        if(!is_array($data)) $data = [];
        $data = array_merge($def, $data);
        $data['enabled'] = ((string)($data['enabled'] ?? '') === '✅فعال') ? '✅فعال' : '❌غیر فعال';
        $data['channel_id'] = trim((string)($data['channel_id'] ?? ''));
        return $data;
    }
}

if (!function_exists('bot_zibal_receipt_log')) {
    function bot_zibal_receipt_log($message, array $context=[]){
        $root = defined('BOT_ROOT_DIR') ? rtrim((string)BOT_ROOT_DIR, '/') : rtrim(dirname(__DIR__, 2), '/');
        $dir = $root . '/cache';
        if(!is_dir($dir)) @mkdir($dir, 0775, true);
        $line = date('c') . ' | ' . $message;
        if($context) $line .= ' | ' . json_encode($context, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        @file_put_contents($dir . '/zibal_receipt_channel.log', $line."\n", FILE_APPEND);
    }
}

if (!function_exists('bot_zibal_receipt_channel_text')) {
    function bot_zibal_receipt_channel_text($trackId, array $payment, array $verify=[], $balanceAfter=0){
        $userId = (string)($payment['user_id'] ?? '');
        $amount = (int)($payment['amount'] ?? 0);
        $reward = (int)($payment['reward_amount'] ?? 0);
        $orderId = (string)($payment['order_id'] ?? '');
        $desc = trim((string)($payment['description'] ?? ''));
        $ref = (string)($verify['refNumber'] ?? ($verify['ref_number'] ?? ''));
        $card = (string)($verify['cardNumber'] ?? ($verify['card_number'] ?? ''));
        $paidAt = isset($payment['paid_at']) ? (int)$payment['paid_at'] : time();
        $txt = "✅ <b>پرداخت آنلاین زیبال موفق</b>\n\n".
            "👤 کاربر: <code>".bot_zibal_receipt_html($userId)."</code>\n".
            "💳 مبلغ پرداختی: <b>".bot_zibal_receipt_html(bot_zibal_receipt_format_money($amount))."</b>\n".
            "💎 مقدار شارژ: <b>".number_format($reward)."</b>\n";
        if((int)$balanceAfter > 0) $txt .= "💰 موجودی جدید کاربر: <b>".number_format((int)$balanceAfter)."</b>\n";
        if($desc !== '') $txt .= "📦 توضیح/بسته: <b>".bot_zibal_receipt_html($desc)."</b>\n";
        $txt .= "\n🧾 Track ID: <code>".bot_zibal_receipt_html($trackId)."</code>";
        if($orderId !== '') $txt .= "\n🔢 Order ID: <code>".bot_zibal_receipt_html($orderId)."</code>";
        if($ref !== '') $txt .= "\n🔖 کد پیگیری: <code>".bot_zibal_receipt_html($ref)."</code>";
        if($card !== '') $txt .= "\n💳 کارت پرداخت‌کننده: <code>".bot_zibal_receipt_html($card)."</code>";
        $txt .= "\n⏰ زمان ثبت: <code>".date('Y-m-d H:i:s', $paidAt)."</code>";
        return $txt;
    }
}

if (!function_exists('bot_zibal_receipt_notify_channel')) {
    function bot_zibal_receipt_notify_channel($trackId, array $payment, array $verify=[], $balanceAfter=0){
        $settings = bot_zibal_receipt_channel_settings();
        if((string)($settings['enabled'] ?? '') !== '✅فعال'){
            bot_zibal_receipt_log('skip_disabled', ['trackId'=>$trackId]);
            return ['ok'=>false,'skipped'=>'disabled'];
        }
        $target = trim((string)($settings['channel_id'] ?? ''));
        if($target === ''){
            bot_zibal_receipt_log('skip_empty_channel', ['trackId'=>$trackId]);
            return ['ok'=>false,'skipped'=>'empty_channel'];
        }
        $text = bot_zibal_receipt_channel_text($trackId, $payment, $verify, $balanceAfter);
        if(!function_exists('bot')){
            bot_zibal_receipt_log('bot_function_missing', ['trackId'=>$trackId,'target'=>$target]);
            return ['ok'=>false,'error'=>'bot_function_missing'];
        }
        $res = bot('sendMessage', ['chat_id'=>$target, 'text'=>$text, 'parse_mode'=>'HTML']);
        $ok = is_object($res) && !empty($res->ok);
        $out = [
            'ok'=>$ok,
            'chat_id'=>$target,
            'message_id'=>($ok && isset($res->result->message_id)) ? (int)$res->result->message_id : 0,
            'error'=>$ok ? '' : (isset($res->description) ? (string)$res->description : 'send_failed'),
            'sent_at'=>time(),
        ];
        bot_zibal_receipt_log($ok ? 'sent' : 'failed', ['trackId'=>$trackId] + $out);
        return $out;
    }
}

if (!function_exists('bot_zibal_request_payment')) {
    function bot_zibal_request_payment($userId, $amount, $description, $mobile='', $type='coin', $rewardAmount=0, array $meta=[]){
        $cfg = bot_zibal_cfg();
        if($cfg['merchant_id'] === '') return ['ok'=>false,'error'=>'merchant_not_set'];
        if($cfg['callback_url'] === '') return ['ok'=>false,'error'=>'callback_not_set'];
        $amount = (int)$amount;
        if($amount <= 0) return ['ok'=>false,'error'=>'bad_amount'];
        $orderId = 'bot_'.$userId.'_'.time().'_'.mt_rand(1000,9999);
        $payload = [
            'merchant' => $cfg['merchant_id'],
            'amount' => $amount,
            'callbackUrl' => $cfg['callback_url'],
            'description' => mb_substr((string)$description, 0, 255, 'UTF-8'),
            'orderId' => $orderId,
        ];
        if($mobile !== '') $payload['mobile'] = (string)$mobile;
        $res = bot_zibal_curl_json($cfg['api_request'], $payload);
        if(empty($res['ok'])) return $res;
        $data = $res['json'];
        $trackId = (string)($data['trackId'] ?? '');
        $code = (int)($data['result'] ?? 0);
        if($trackId === '' || $code !== 100) return ['ok'=>false,'error'=>'zibal_'.$code,'response'=>$res['json']];
        $all = bot_zibal_payment_store_read();
        $all[$trackId] = [
            'trackId'=>$trackId,
            'track_id'=>$trackId,
            'order_id'=>$orderId,
            'user_id'=>(string)$userId,
            'amount'=>$amount,
            'description'=>(string)$description,
            'type'=>(string)$type,
            'reward_amount'=>(int)$rewardAmount,
            'meta'=>$meta,
            'status'=>'created',
            'created_at'=>time(),
            'gateway'=>'zibal',
            'request_response'=>$res['json'],
        ];
        bot_zibal_payment_store_write($all);
        return ['ok'=>true,'trackId'=>$trackId,'track_id'=>$trackId,'authority'=>$trackId,'payment_url'=>$cfg['start_base'].$trackId,'response'=>$res['json']];
    }
}

if (!function_exists('bot_zibal_verify_payment')) {
    function bot_zibal_verify_payment($trackId, $status=null){
        $cfg = bot_zibal_cfg();
        $trackId = trim((string)$trackId);
        $all = bot_zibal_payment_store_read();
        if($trackId === '' || !isset($all[$trackId])) return ['ok'=>false,'error'=>'payment_not_found'];
        $p = $all[$trackId];
        if(($p['status'] ?? '') === 'paid') return ['ok'=>true,'already_paid'=>true,'payment'=>$p];

        // Zibal redirects with status=2 after successful bank payment. If status is present and not 2, mark as cancelled/failed.
        if($status !== null && $status !== '' && (string)$status !== '2'){
            $all[$trackId]['status']='cancelled';
            $all[$trackId]['cancel_status']=(string)$status;
            bot_zibal_payment_store_write($all);
            return ['ok'=>false,'error'=>'cancelled','status'=>(string)$status];
        }
        $res = bot_zibal_curl_json($cfg['api_verify'], [
            'merchant'=>$cfg['merchant_id'],
            'trackId'=>$trackId,
        ]);
        if(empty($res['ok'])) return $res;
        $data = $res['json'];
        $code = (int)($data['result'] ?? 0);
        if($code !== 100 && $code !== 201) return ['ok'=>false,'error'=>'verify_'.$code,'response'=>$res['json']];
        $balanceAfter = 0;
        $walletAddResult = null;
        $isSponsorPayment = ((string)($p['type'] ?? '') === 'sponsor');
        $isReactionPayment = ((string)($p['type'] ?? '') === 'reaction');
        if(!$isSponsorPayment && !$isReactionPayment && function_exists('bot_simple_add_points_to_user') && (int)$p['reward_amount'] > 0){
            $walletAddResult = bot_simple_add_points_to_user($p['user_id'], (int)$p['reward_amount'], 'zibal_shop', ['trackId'=>$trackId,'refNumber'=>$data['refNumber'] ?? ($data['ref_number'] ?? '')]);
            if(is_array($walletAddResult) && isset($walletAddResult['after'])) $balanceAfter = (int)$walletAddResult['after'];
        }
        $all[$trackId]['status']='paid';
        $all[$trackId]['paid_at']=time();
        $all[$trackId]['verify']=$data;
        $all[$trackId]['gateway']='zibal';
        $all[$trackId]['wallet_add_result']=$walletAddResult;
        $all[$trackId]['balance_after']=$balanceAfter;
        if($isSponsorPayment && function_exists('bot_sponsor_on_zibal_paid')){
            $sponsorRes = bot_sponsor_on_zibal_paid($trackId, $all[$trackId], $data);
            $all[$trackId]['sponsor_result'] = $sponsorRes;
        }
        if($isReactionPayment && function_exists('bot_reaction_on_zibal_paid')){
            $reactionRes = bot_reaction_on_zibal_paid($trackId, $all[$trackId], $data);
            $all[$trackId]['reaction_result'] = $reactionRes;
        }
        if(function_exists('bot_zibal_receipt_notify_channel')){
            $notifyRes = bot_zibal_receipt_notify_channel($trackId, $all[$trackId], $data, $balanceAfter);
            $all[$trackId]['receipt_channel_notify']=$notifyRes;
        }
        bot_zibal_payment_store_write($all);
        if(function_exists('bot_payment_event_log_append')){
            bot_payment_event_log_append([
                'source'=>'zibal',
                'id'=>'zibal_'.$trackId,
                'trackId'=>(string)$trackId,
                'track_id'=>(string)$trackId,
                'order_id'=>(string)($p['order_id'] ?? ''),
                'ref_id'=>(string)($data['refNumber'] ?? ($data['ref_number'] ?? '')),
                'refNumber'=>(string)($data['refNumber'] ?? ($data['ref_number'] ?? '')),
                'card_number'=>(string)($data['cardNumber'] ?? ($data['card_number'] ?? '')),
                'user_id'=>(string)($p['user_id'] ?? ''),
                'amount'=>(int)($p['amount'] ?? 0),
                'reward_amount'=>(int)($p['reward_amount'] ?? 0),
                'description'=>(string)($p['description'] ?? ''),
                'type'=>(string)($p['type'] ?? ''),
                'status'=>'paid',
                'created_at'=>$p['created_at'] ?? time(),
                'paid_at'=>time(),
                'balance_after'=>$balanceAfter,
                'receipt_channel_notify'=>$all[$trackId]['receipt_channel_notify'] ?? null,
                'verify'=>$data,
                'raw_payment'=>$all[$trackId],
            ]);
        }
        return ['ok'=>true,'code'=>$code,'payment'=>$all[$trackId], 'verify'=>$data];
    }
}

// Compatibility wrappers: old shop routes still call bot_zp_*.
if (!function_exists('bot_zp_cfg')) { function bot_zp_cfg(){ return bot_zibal_cfg(); } }
if (!function_exists('bot_zp_curl_json')) { function bot_zp_curl_json($url, array $payload){ return bot_zibal_curl_json($url, $payload); } }
if (!function_exists('bot_zp_payment_store_path')) { function bot_zp_payment_store_path(){ return bot_zibal_payment_store_path(); } }
if (!function_exists('bot_zp_payment_store_read')) { function bot_zp_payment_store_read(){ return bot_zibal_payment_store_read(); } }
if (!function_exists('bot_zp_payment_store_write')) { function bot_zp_payment_store_write(array $v){ return bot_zibal_payment_store_write($v); } }
if (!function_exists('bot_zp_request_payment')) { function bot_zp_request_payment($userId, $amount, $description, $mobile='', $type='coin', $rewardAmount=0, array $meta=[]){ return bot_zibal_request_payment($userId, $amount, $description, $mobile, $type, $rewardAmount, $meta); } }
if (!function_exists('bot_zp_verify_payment')) { function bot_zp_verify_payment($trackId, $status=null){ return bot_zibal_verify_payment($trackId, $status); } }
