<?php
/**
 * Daily diamond reward service.
 * - Admin configurable amount and interval.
 * - SQL-backed claim tracking for speed and duplicate protection.
 * - Keeps legacy time-day/mdailys values compatible.
 */

if(!function_exists('bot_daily_default_settings')){
    function bot_daily_default_settings(){
        return [
            'enabled' => '✅فعال',
            'amount' => 3,
            'interval_days' => 1,
            'channel_button_enabled' => '✅فعال',
            'notify_enabled' => '❌غیر فعال',
            'notify_text' => "🎁 **الماس روزانه شما آماده دریافت است**\nهدیه امروز شما AMOUNT MONEY است.\nبرای دریافت، روی دکمه زیر بزنید.",
            'success_text' => "✅ تبریک!\nبرای این دوره AMOUNT MONEY به حساب شما اضافه شد.\nموجودی فعلی: BALANCE MONEY\nدریافت بعدی بعد از DAYS روز امکان‌پذیر است.",
            'cooldown_text' => "⏱ شما قبلاً هدیه این دوره را دریافت کرده‌اید.\nزمان باقی‌مانده: REMAINING",
        ];
    }
}

if(!function_exists('bot_daily_clean_int')){
    function bot_daily_clean_int($value){
        if(function_exists('bot_normalize_number_digits')) $value = bot_normalize_number_digits($value);
        $value = preg_replace('/[^0-9\-]/', '', (string)$value);
        return (int)$value;
    }
}

if(!function_exists('bot_daily_settings')){
    function bot_daily_settings(){
        $s = function_exists('bot_data_get_json') ? bot_data_get_json('lib/kodam/data-daily.json', []) : [];
        if(!is_array($s)) $s = [];
        $s = array_merge(bot_daily_default_settings(), $s);

        // Backward compatibility: if an old mdailys1 value exists and no explicit amount was saved yet.
        if(!isset($s['amount']) || bot_daily_clean_int($s['amount']) <= 0){
            $legacy = function_exists('bot_data_get_text') ? bot_data_get_text('lib/Button/mdailys1.txt', '') : (is_file('lib/Button/mdailys1.txt') ? file_get_contents('lib/Button/mdailys1.txt') : '');
            $n = bot_daily_clean_int($legacy);
            $s['amount'] = $n > 0 ? $n : 3;
        }
        $s['amount'] = max(1, bot_daily_clean_int($s['amount']));
        $s['interval_days'] = max(1, bot_daily_clean_int($s['interval_days']));
        $s['enabled'] = ((string)($s['enabled'] ?? '✅فعال') === '❌غیر فعال') ? '❌غیر فعال' : '✅فعال';
        $s['channel_button_enabled'] = ((string)($s['channel_button_enabled'] ?? '✅فعال') === '❌غیر فعال') ? '❌غیر فعال' : '✅فعال';
        $s['notify_enabled'] = ((string)($s['notify_enabled'] ?? '❌غیر فعال') === '✅فعال') ? '✅فعال' : '❌غیر فعال';
        if(!isset($s['notify_text']) || trim((string)$s['notify_text']) === ''){
            $s['notify_text'] = bot_daily_default_settings()['notify_text'];
        }
        return $s;
    }
}

if(!function_exists('bot_daily_save_settings')){
    function bot_daily_save_settings(array $settings){
        $old = bot_daily_settings();
        $s = array_merge($old, $settings);
        $s['amount'] = max(1, bot_daily_clean_int($s['amount'] ?? 3));
        $s['interval_days'] = max(1, bot_daily_clean_int($s['interval_days'] ?? 1));
        $s['enabled'] = ((string)($s['enabled'] ?? '✅فعال') === '❌غیر فعال') ? '❌غیر فعال' : '✅فعال';
        $s['channel_button_enabled'] = ((string)($s['channel_button_enabled'] ?? '✅فعال') === '❌غیر فعال') ? '❌غیر فعال' : '✅فعال';
        $s['notify_enabled'] = ((string)($s['notify_enabled'] ?? '❌غیر فعال') === '✅فعال') ? '✅فعال' : '❌غیر فعال';
        if(!isset($s['notify_text']) || trim((string)$s['notify_text']) === ''){
            $s['notify_text'] = bot_daily_default_settings()['notify_text'];
        }
        if(function_exists('saveJson')) saveJson('lib/kodam/data-daily.json', $s);
        elseif(function_exists('bot_data_put_json')) bot_data_put_json('lib/kodam/data-daily.json', $s);
        else {
            if(!is_dir('lib/kodam')) @mkdir('lib/kodam', 0755, true);
            @file_put_contents('lib/kodam/data-daily.json', json_encode($s, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
        }
        // Keep old panel settings in sync so any leftover legacy route still pays the same amount.
        foreach(['mdailys1','mdailys2','mdailys3'] as $k){
            if(function_exists('Save')) Save('lib/Button/'.$k.'.txt', (string)$s['amount']);
            elseif(function_exists('bot_data_put_raw')) bot_data_put_raw('lib/Button/'.$k.'.txt', (string)$s['amount']);
            else @file_put_contents('lib/Button/'.$k.'.txt', (string)$s['amount']);
        }
        return true;
    }
}

if(!function_exists('bot_daily_pdo')){
    function bot_daily_pdo(){ return function_exists('bot_sql_pdo') ? bot_sql_pdo() : null; }
}

if(!function_exists('bot_daily_install_schema')){
    function bot_daily_install_schema(){
        $pdo = bot_daily_pdo();
        if(!$pdo) return false;
        try{
            $pdo->exec("CREATE TABLE IF NOT EXISTS bot_daily_rewards (
                user_id VARCHAR(32) NOT NULL PRIMARY KEY,
                last_claim_ts BIGINT NOT NULL DEFAULT 0,
                next_claim_ts BIGINT NOT NULL DEFAULT 0,
                claim_count INT NOT NULL DEFAULT 0,
                total_amount INT NOT NULL DEFAULT 0,
                data_json LONGTEXT NULL,
                updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                KEY idx_next_claim (next_claim_ts),
                KEY idx_updated (updated_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
            $pdo->exec("CREATE TABLE IF NOT EXISTS bot_daily_reward_events (
                id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
                user_id VARCHAR(32) NOT NULL,
                amount INT NOT NULL DEFAULT 0,
                before_balance INT NULL,
                after_balance INT NULL,
                status VARCHAR(30) NOT NULL DEFAULT 'claimed',
                data_json LONGTEXT NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                KEY idx_user_created (user_id, created_at),
                KEY idx_status (status),
                KEY idx_created (created_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
            $pdo->exec("CREATE TABLE IF NOT EXISTS bot_daily_notify_jobs (
                id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
                job_key VARCHAR(80) NOT NULL,
                source VARCHAR(20) NOT NULL DEFAULT 'auto',
                status VARCHAR(20) NOT NULL DEFAULT 'queued',
                message_text LONGTEXT NULL,
                total INT NOT NULL DEFAULT 0,
                processed INT NOT NULL DEFAULT 0,
                success INT NOT NULL DEFAULT 0,
                failed INT NOT NULL DEFAULT 0,
                last_user_id VARCHAR(32) NOT NULL DEFAULT '0',
                last_error VARCHAR(255) NULL,
                created_ts BIGINT NOT NULL DEFAULT 0,
                started_ts BIGINT NOT NULL DEFAULT 0,
                finished_ts BIGINT NOT NULL DEFAULT 0,
                data_json LONGTEXT NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                UNIQUE KEY uniq_daily_job_key (job_key),
                KEY idx_daily_status (status, id),
                KEY idx_daily_source_created (source, created_ts),
                KEY idx_daily_updated (updated_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
            return true;
        }catch(Throwable $e){
            error_log('BOT daily reward schema failed: '.$e->getMessage());
            return false;
        }
    }
}

if(!function_exists('bot_daily_json')){
    function bot_daily_json(array $data){
        return function_exists('bot_json_encode') ? bot_json_encode($data) : json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
}

if(!function_exists('bot_daily_log_event')){
    function bot_daily_log_event($userId, $amount, $before, $after, $status, array $data=[]){
        $pdo = bot_daily_pdo();
        if(!$pdo) return false;
        bot_daily_install_schema();
        try{
            $st = $pdo->prepare('INSERT INTO bot_daily_reward_events (user_id, amount, before_balance, after_balance, status, data_json) VALUES (?,?,?,?,?,?)');
            $st->execute([(string)$userId, (int)$amount, $before === null ? null : (int)$before, $after === null ? null : (int)$after, (string)$status, bot_daily_json($data)]);
            return true;
        }catch(Throwable $e){
            error_log('BOT daily event failed: '.$e->getMessage());
            return false;
        }
    }
}

if(!function_exists('bot_daily_remaining_text')){
    function bot_daily_remaining_text($seconds){
        $seconds = max(0, (int)$seconds);
        $days = intdiv($seconds, 86400);
        $seconds %= 86400;
        $hours = intdiv($seconds, 3600);
        $seconds %= 3600;
        $minutes = intdiv($seconds, 60);
        if($days > 0) return $days.' روز و '.$hours.' ساعت';
        if($hours > 0) return $hours.' ساعت و '.$minutes.' دقیقه';
        return max(1, $minutes).' دقیقه';
    }
}

if(!function_exists('bot_daily_apply_text')){
    function bot_daily_apply_text($text, array $vars=[]){
        if(function_exists('bot_text_settings_apply_vars')) return bot_text_settings_apply_vars($text, $vars);
        foreach($vars as $k=>$v){
            $text = str_replace([$k, '{'.$k.'}'], (string)$v, (string)$text);
        }
        return (string)$text;
    }
}

if(!function_exists('bot_daily_channel_url')){
    function bot_daily_channel_url($channel){
        $channel = trim((string)$channel);
        if($channel === '') return '';
        if(preg_match('~^https?://~i', $channel)) return $channel;
        if($channel[0] === '@') $channel = substr($channel, 1);
        // Numeric private channel ids cannot be opened by public URL.
        if(preg_match('/^-?\d+$/', $channel)) return '';
        return 'https://t.me/'.rawurlencode($channel);
    }
}

if(!function_exists('bot_daily_user_keyboard')){
    function bot_daily_user_keyboard(){
        global $chads;
        // User panel requirement: two inline buttons side-by-side and with stable labels.
        $row = [[ 'text'=>'الماس روزانه', 'callback_data'=>'dailygiftt' ]];
        $url = bot_daily_channel_url($chads ?? '');
        if($url !== '') $row[] = [ 'text'=>'کانال سفارشات', 'url'=>$url ];
        else $row[] = [ 'text'=>'کانال سفارشات', 'callback_data'=>'daily_order_channel_missing' ];
        return json_encode(['inline_keyboard'=>[$row]], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
}

if(!function_exists('bot_daily_admin_text')){
    function bot_daily_admin_text(){
        global $money, $icmoney;
        $s = bot_daily_settings();
        return "🎁 **تنظیمات الماس روزانه**\n\n".
            "وضعیت: **{$s['enabled']}**\n".
            "مقدار هدیه: **".number_format((int)$s['amount'])."** ".($money ?? 'الماس')." ".($icmoney ?? '💎')."\n".
            "فاصله دریافت: هر **".(int)$s['interval_days']." روز**\n".
            "دکمه کاربر: **💎 جمع اوری الماس**\n".
            "دکمه‌های شیشه‌ای کاربر: **الماس روزانه** و **کانال سفارشات**\n\n".
            "الماس روزانه از پنل کاربر دریافت می‌شود. از اینجا فقط مقدار هدیه و فاصله دریافت را تنظیم کن. لینک دکمه کانال سفارشات هم از بخش 🆔 تنظیم کانال خوانده می‌شود.";
    }
}

if(!function_exists('bot_daily_admin_keyboard')){
    function bot_daily_admin_keyboard(){
        $s = bot_daily_settings();
        return json_encode(['inline_keyboard'=>[
            [[ 'text'=>((string)$s['enabled']==='✅فعال'?'✅ روشن':'❌ خاموش'), 'callback_data'=>'dailyadm_toggle_enabled' ]],
            [[ 'text'=>'💎 مقدار هدیه: '.number_format((int)$s['amount']), 'callback_data'=>'dailyadm_set_amount' ], [ 'text'=>'📆 فاصله: '.(int)$s['interval_days'].' روز', 'callback_data'=>'dailyadm_set_days' ]],
            [[ 'text'=>'🔄 ریست زمان دریافت همه کاربران', 'callback_data'=>'dailyadm_reset_all' ]],
            [[ 'text'=>'🔙 بازگشت به پنل', 'callback_data'=>'admin_main_menu' ]],
        ]], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
}

if(!function_exists('bot_daily_claim')){
    function bot_daily_claim($userId){
        $s = bot_daily_settings();
        $now = time();
        $amount = (int)$s['amount'];
        $interval = max(1, (int)$s['interval_days']) * 86400;
        if((string)$s['enabled'] === '❌غیر فعال'){
            return ['ok'=>false, 'error'=>'disabled', 'message'=>'❌ الماس روزانه فعلاً غیرفعال است.'];
        }

        $pdo = bot_daily_pdo();
        if($pdo){
            bot_daily_install_schema();
            try{
                $pdo->prepare('INSERT IGNORE INTO bot_daily_rewards (user_id, last_claim_ts, next_claim_ts, claim_count, total_amount, data_json) VALUES (?,0,0,0,0,?)')
                    ->execute([(string)$userId, bot_daily_json(['created_at'=>$now])]);
                $future = $now + $interval;
                $st = $pdo->prepare('UPDATE bot_daily_rewards SET last_claim_ts=?, next_claim_ts=?, claim_count=claim_count+1, total_amount=total_amount+?, data_json=?, updated_at=CURRENT_TIMESTAMP WHERE user_id=? AND next_claim_ts<=?');
                $st->execute([$now, $future, $amount, bot_daily_json(['amount'=>$amount,'interval_days'=>(int)$s['interval_days'],'claimed_at'=>$now]), (string)$userId, $now]);
                if($st->rowCount() < 1){
                    $q = $pdo->prepare('SELECT next_claim_ts FROM bot_daily_rewards WHERE user_id=? LIMIT 1');
                    $q->execute([(string)$userId]);
                    $next = (int)$q->fetchColumn();
                    return ['ok'=>false, 'error'=>'cooldown', 'remaining'=>max(0, $next-$now), 'next'=>$next];
                }
            }catch(Throwable $e){
                error_log('BOT daily claim SQL failed: '.$e->getMessage());
                // Continue with file fallback.
                $pdo = null;
            }
        }

        if(!$pdo){
            $u = function_exists('bot_data_get_json') ? bot_data_get_json('melat/'.$userId.'.json', []) : [];
            if(!is_array($u)) $u = [];
            $next = (int)($u['daily_next_ts'] ?? ($u['time-day'] ?? 0));
            if($next > $now){
                return ['ok'=>false, 'error'=>'cooldown', 'remaining'=>max(0, $next-$now), 'next'=>$next];
            }
            $u['daily_last_ts'] = $now;
            $u['daily_next_ts'] = $now + $interval;
            $u['time-day'] = (string)($now + $interval);
            if(function_exists('saveJson')) saveJson('melat/'.$userId.'.json', $u);
            elseif(function_exists('bot_data_put_json')) bot_data_put_json('melat/'.$userId.'.json', $u);
        }

        if(function_exists('bot_wallet_add')) $res = bot_wallet_add($userId, $amount, 'daily_reward', ['interval_days'=>(int)$s['interval_days']]);
        elseif(function_exists('bot_simple_add_points_to_user')) $res = bot_simple_add_points_to_user($userId, $amount, 'daily_reward', ['interval_days'=>(int)$s['interval_days']]);
        else $res = ['ok'=>false, 'error'=>'wallet_unavailable'];

        if(empty($res['ok'])){
            bot_daily_log_event($userId, $amount, null, null, 'wallet_failed', ['error'=>$res['error'] ?? 'unknown']);
            return ['ok'=>false, 'error'=>'wallet_failed', 'message'=>'❌ خطا در شارژ حساب. دوباره تلاش کنید یا به پشتیبانی پیام دهید.'];
        }
        // Keep legacy user fields compatible with older views/routes.
        $compatUser = is_array($res['data'] ?? null) ? $res['data'] : (function_exists('bot_data_get_json') ? bot_data_get_json('melat/'.$userId.'.json', []) : []);
        if(is_array($compatUser)){
            $compatUser['daily_last_ts'] = $now;
            $compatUser['daily_next_ts'] = $now + $interval;
            $compatUser['time-day'] = (string)($now + $interval);
            if(function_exists('saveJson')) saveJson('melat/'.$userId.'.json', $compatUser);
            elseif(function_exists('bot_data_put_json')) bot_data_put_json('melat/'.$userId.'.json', $compatUser);
        }
        bot_daily_log_event($userId, $amount, $res['before'] ?? null, $res['after'] ?? null, 'claimed', ['interval_days'=>(int)$s['interval_days']]);
        return ['ok'=>true, 'amount'=>$amount, 'before'=>$res['before'] ?? 0, 'after'=>$res['after'] ?? 0, 'interval_days'=>(int)$s['interval_days'], 'next'=>$now+$interval];
    }
}


if(!function_exists('bot_daily_notify_keyboard')){
    function bot_daily_notify_keyboard(){
        return json_encode(['inline_keyboard'=>[
            [[ 'text'=>'الماس روزانه', 'callback_data'=>'dailygiftt' ]]
        ]], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
}

if(!function_exists('bot_daily_notify_text')){
    function bot_daily_notify_text(){
        global $money, $icmoney;
        $s = bot_daily_settings();
        return bot_daily_apply_text((string)$s['notify_text'], [
            'AMOUNT'=>number_format((int)$s['amount']),
            'DAYS'=>(string)$s['interval_days'],
            'MONEY'=>$money ?? 'الماس',
            'ICMONEY'=>$icmoney ?? '💎',
        ]);
    }
}

if(!function_exists('bot_daily_notify_queue_file')){
    function bot_daily_notify_queue_file(){
        $dir = dirname(dirname(__DIR__)).'/cache';
        if(!is_dir($dir)) @mkdir($dir, 0775, true);
        return $dir.'/daily_notify_queue.json';
    }
}

if(!function_exists('bot_daily_notify_lock_file')){
    function bot_daily_notify_lock_file(){
        $dir = dirname(dirname(__DIR__)).'/cache';
        if(!is_dir($dir)) @mkdir($dir, 0775, true);
        return $dir.'/daily_notify.lock';
    }
}

if(!function_exists('bot_daily_notify_user_ids_fallback')){
    function bot_daily_notify_user_ids_fallback(){
        if(function_exists('bot_broadcast_user_ids')) return bot_broadcast_user_ids(false);
        $ids = [];
        $files = function_exists('bot_data_glob') ? bot_data_glob('melat/*.json') : (glob(dirname(dirname(__DIR__)).'/melat/*.json') ?: []);
        foreach($files as $file){
            $id = basename((string)$file, '.json');
            if(is_numeric($id) && $id !== '0') $ids[] = (string)$id;
        }
        return array_values(array_unique($ids));
    }
}

if(!function_exists('bot_daily_notify_active_sql')){
    function bot_daily_notify_active_sql(PDO $pdo){
        bot_daily_install_schema();
        $st = $pdo->query("SELECT * FROM bot_daily_notify_jobs WHERE status IN ('queued','running') ORDER BY id ASC LIMIT 1");
        $row = $st ? $st->fetch() : null;
        return is_array($row) ? $row : null;
    }
}

if(!function_exists('bot_daily_notify_count_users_sql')){
    function bot_daily_notify_count_users_sql(PDO $pdo){
        try{
            return (int)$pdo->query("SELECT COUNT(*) FROM bot_users WHERE user_id REGEXP '^[0-9]+$' AND user_id <> '0'")->fetchColumn();
        }catch(Throwable $e){
            try{ return (int)$pdo->query("SELECT COUNT(*) FROM bot_users WHERE user_id <> '0'")->fetchColumn(); }
            catch(Throwable $e2){ return 0; }
        }
    }
}

if(!function_exists('bot_daily_notify_next_users_sql')){
    function bot_daily_notify_next_users_sql(PDO $pdo, $lastUserId, $limit){
        $limit = max(1, min(50, (int)$limit));
        $last = max(0, (int)$lastUserId);
        try{
            $st = $pdo->prepare("SELECT user_id FROM bot_users WHERE user_id REGEXP '^[0-9]+$' AND CAST(user_id AS UNSIGNED) > ? ORDER BY CAST(user_id AS UNSIGNED) ASC LIMIT {$limit}");
            $st->execute([$last]);
            $rows = $st->fetchAll();
        }catch(Throwable $e){
            $st = $pdo->prepare("SELECT user_id FROM bot_users WHERE user_id > ? ORDER BY user_id ASC LIMIT {$limit}");
            $st->execute([(string)$lastUserId]);
            $rows = $st->fetchAll();
        }
        $ids = [];
        foreach((array)$rows as $r){
            $id = is_array($r) ? ($r['user_id'] ?? '') : '';
            if((string)$id !== '' && (string)$id !== '0') $ids[] = (string)$id;
        }
        return $ids;
    }
}

if(!function_exists('bot_daily_cron_start_job')){
    function bot_daily_cron_start_job($source='manual', $force=false){
        $s = bot_daily_settings();
        $source = ((string)$source === 'auto') ? 'auto' : 'manual';
        if((string)$s['enabled'] === '❌غیر فعال') return ['ok'=>false, 'error'=>'daily_disabled'];
        if((string)$s['notify_enabled'] === '❌غیر فعال') return ['ok'=>false, 'error'=>'notify_disabled'];

        $pdo = bot_daily_pdo();
        if($pdo){
            bot_daily_install_schema();
            try{
                $active = bot_daily_notify_active_sql($pdo);
                if($active) return ['ok'=>true, 'status'=>'active', 'job'=>$active];
                $jobKey = $source === 'auto' ? ('daily_auto_'.date('Ymd')) : ('daily_manual_'.date('Ymd_His').'_'.substr(sha1(microtime(true).mt_rand()),0,6));
                if($source === 'auto'){
                    $st = $pdo->prepare('SELECT * FROM bot_daily_notify_jobs WHERE job_key=? LIMIT 1');
                    $st->execute([$jobKey]);
                    $exists = $st->fetch();
                    if($exists) return ['ok'=>true, 'status'=>'already_created_today', 'job'=>$exists];
                }
                $total = bot_daily_notify_count_users_sql($pdo);
                $text = bot_daily_notify_text();
                $st = $pdo->prepare('INSERT INTO bot_daily_notify_jobs (job_key, source, status, message_text, total, created_ts, data_json) VALUES (?,?,?,?,?,?,?)');
                $st->execute([$jobKey, $source, 'queued', $text, $total, time(), bot_daily_json(['amount'=>(int)$s['amount'], 'interval_days'=>(int)$s['interval_days']])]);
                $id = (int)$pdo->lastInsertId();
                $q = $pdo->prepare('SELECT * FROM bot_daily_notify_jobs WHERE id=? LIMIT 1');
                $q->execute([$id]);
                return ['ok'=>true, 'status'=>'queued', 'job'=>$q->fetch()];
            }catch(Throwable $e){
                error_log('BOT daily notify start failed: '.$e->getMessage());
                return ['ok'=>false, 'error'=>$e->getMessage()];
            }
        }

        // File fallback for hosts without SQL.
        $file = bot_daily_notify_queue_file();
        $q = is_file($file) ? json_decode((string)@file_get_contents($file), true) : [];
        if(!is_array($q)) $q = [];
        if(isset($q['status']) && in_array((string)$q['status'], ['queued','running'], true)) return ['ok'=>true, 'status'=>'active', 'job'=>$q];
        if($source === 'auto' && isset($q['job_key']) && (string)$q['job_key'] === 'daily_auto_'.date('Ymd')) return ['ok'=>true, 'status'=>'already_created_today', 'job'=>$q];
        $ids = bot_daily_notify_user_ids_fallback();
        $q = ['job_key'=>$source==='auto'?'daily_auto_'.date('Ymd'):'daily_manual_'.date('Ymd_His'), 'source'=>$source, 'status'=>'queued', 'message_text'=>bot_daily_notify_text(), 'ids'=>$ids, 'offset'=>0, 'total'=>count($ids), 'success'=>0, 'failed'=>0, 'created_ts'=>time(), 'last_error'=>''];
        @file_put_contents($file, json_encode($q, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT), LOCK_EX);
        return ['ok'=>true, 'status'=>'queued', 'job'=>$q];
    }
}

if(!function_exists('bot_daily_cron_status')){
    function bot_daily_cron_status(){
        $pdo = bot_daily_pdo();
        if($pdo){
            bot_daily_install_schema();
            try{
                $active = bot_daily_notify_active_sql($pdo);
                $last = $pdo->query('SELECT * FROM bot_daily_notify_jobs ORDER BY id DESC LIMIT 1')->fetch();
                return ['ok'=>true, 'driver'=>'sql', 'active'=>$active ?: null, 'last'=>is_array($last)?$last:null];
            }catch(Throwable $e){ return ['ok'=>false, 'driver'=>'sql', 'error'=>$e->getMessage()]; }
        }
        $file = bot_daily_notify_queue_file();
        $q = is_file($file) ? json_decode((string)@file_get_contents($file), true) : [];
        return ['ok'=>true, 'driver'=>'file', 'active'=>(isset($q['status']) && in_array((string)$q['status'], ['queued','running'], true))?$q:null, 'last'=>is_array($q)?$q:null];
    }
}

if(!function_exists('bot_daily_cron_status_line')){
    function bot_daily_cron_status_line(){
        $s = bot_daily_settings();
        $st = bot_daily_cron_status();
        $line = "کرون پیام روزانه: **".$s['notify_enabled']."**";
        $job = $st['active'] ?? ($st['last'] ?? null);
        if(is_array($job) && !empty($job)){
            $status = (string)($job['status'] ?? '-');
            $processed = (int)($job['processed'] ?? ($job['offset'] ?? 0));
            $total = (int)($job['total'] ?? 0);
            $success = (int)($job['success'] ?? 0);
            $failed = (int)($job['failed'] ?? 0);
            $line .= "\nآخرین/فعلی: **{$status}** | {$processed}/{$total} | ✅ {$success} | ❌ {$failed}";
        }else{
            $line .= "\nآخرین/فعلی: هنوز کاری ثبت نشده است.";
        }
        return $line;
    }
}

if(!function_exists('bot_daily_cron_process')){
    function bot_daily_cron_process($limit=20, $maxRuntime=25, $force=false){
        $limit = max(1, min(20, (int)$limit));
        $maxRuntime = max(5, min(55, (int)$maxRuntime));
        $started = time();
        $s = bot_daily_settings();
        if((string)$s['enabled'] === '❌غیر فعال') return ['ok'=>true, 'status'=>'daily_disabled', 'processed'=>0, 'success'=>0, 'failed'=>0];
        if((string)$s['notify_enabled'] === '❌غیر فعال' && !$force) return ['ok'=>true, 'status'=>'notify_disabled', 'processed'=>0, 'success'=>0, 'failed'=>0];

        $lockFile = bot_daily_notify_lock_file();
        $lock = @fopen($lockFile, 'c+');
        if($lock && !@flock($lock, LOCK_EX | LOCK_NB)){
            return ['ok'=>true, 'status'=>'locked', 'processed'=>0, 'success'=>0, 'failed'=>0];
        }

        $release = function() use ($lock){ if($lock){ @flock($lock, LOCK_UN); @fclose($lock); } };

        $pdo = bot_daily_pdo();
        if($pdo){
            bot_daily_install_schema();
            try{
                $job = bot_daily_notify_active_sql($pdo);
                if(!$job){
                    $start = bot_daily_cron_start_job($force ? 'manual' : 'auto', $force);
                    if(empty($start['ok'])){ $release(); return $start + ['processed'=>0,'success'=>0,'failed'=>0]; }
                    $job = bot_daily_notify_active_sql($pdo);
                    if(!$job){ $release(); return ['ok'=>true, 'status'=>$start['status'] ?? 'no_due', 'processed'=>0, 'success'=>0, 'failed'=>0]; }
                }
                if((string)($job['status'] ?? '') === 'queued'){
                    $pdo->prepare("UPDATE bot_daily_notify_jobs SET status='running', started_ts=IF(started_ts=0,?,started_ts), updated_at=CURRENT_TIMESTAMP WHERE id=?")->execute([$started, (int)$job['id']]);
                }
                $ids = bot_daily_notify_next_users_sql($pdo, $job['last_user_id'] ?? '0', $limit);
                if(!$ids){
                    $pdo->prepare("UPDATE bot_daily_notify_jobs SET status='done', finished_ts=?, updated_at=CURRENT_TIMESTAMP WHERE id=?")->execute([time(), (int)$job['id']]);
                    $release();
                    return ['ok'=>true, 'status'=>'done', 'processed'=>0, 'success'=>0, 'failed'=>0];
                }
                $text = trim((string)($job['message_text'] ?? ''));
                if($text === '') $text = bot_daily_notify_text();
                $keyboard = bot_daily_notify_keyboard();
                $processed = $success = $failed = 0;
                $lastUser = (string)($job['last_user_id'] ?? '0');
                $lastError = '';
                foreach($ids as $target){
                    if((time() - $started) >= $maxRuntime) break;
                    $res = bot('sendMessage', [
                        'chat_id'=>(string)$target,
                        'text'=>$text,
                        'parse_mode'=>'MarkDown',
                        'reply_markup'=>$keyboard,
                    ]);
                    $processed++;
                    $lastUser = (string)$target;
                    if(isset($res->ok) && $res->ok){ $success++; }
                    else { $failed++; $lastError = isset($res->description) ? (string)$res->description : 'unknown_error'; }
                }
                $pdo->prepare("UPDATE bot_daily_notify_jobs SET status='running', processed=processed+?, success=success+?, failed=failed+?, last_user_id=?, last_error=?, updated_at=CURRENT_TIMESTAMP WHERE id=?")
                    ->execute([$processed, $success, $failed, $lastUser, $lastError, (int)$job['id']]);
                if($processed < $limit || count($ids) < $limit){
                    // Check if anything remains. If not, close the job.
                    $more = bot_daily_notify_next_users_sql($pdo, $lastUser, 1);
                    if(!$more){
                        $pdo->prepare("UPDATE bot_daily_notify_jobs SET status='done', finished_ts=?, updated_at=CURRENT_TIMESTAMP WHERE id=?")->execute([time(), (int)$job['id']]);
                    }
                }
                $release();
                return ['ok'=>true, 'status'=>'running', 'processed'=>$processed, 'success'=>$success, 'failed'=>$failed, 'job_id'=>(int)$job['id']];
            }catch(Throwable $e){
                $release();
                error_log('BOT daily notify process failed: '.$e->getMessage());
                return ['ok'=>false, 'error'=>$e->getMessage(), 'processed'=>0, 'success'=>0, 'failed'=>0];
            }
        }

        // File fallback.
        $file = bot_daily_notify_queue_file();
        $q = is_file($file) ? json_decode((string)@file_get_contents($file), true) : [];
        if(!is_array($q) || !isset($q['status']) || !in_array((string)$q['status'], ['queued','running'], true)){
            $start = bot_daily_cron_start_job($force ? 'manual' : 'auto', $force);
            $q = is_file($file) ? json_decode((string)@file_get_contents($file), true) : [];
            if(!is_array($q) || !isset($q['status']) || !in_array((string)$q['status'], ['queued','running'], true)){
                $release(); return ['ok'=>true, 'status'=>$start['status'] ?? 'no_due', 'processed'=>0, 'success'=>0, 'failed'=>0];
            }
        }
        $ids = isset($q['ids']) && is_array($q['ids']) ? $q['ids'] : [];
        $offset = max(0, (int)($q['offset'] ?? 0));
        $text = trim((string)($q['message_text'] ?? '')) ?: bot_daily_notify_text();
        $keyboard = bot_daily_notify_keyboard();
        $processed = $success = $failed = 0;
        while($offset < count($ids) && $processed < $limit && (time()-$started) < $maxRuntime){
            $target = (string)$ids[$offset];
            $res = bot('sendMessage', ['chat_id'=>$target, 'text'=>$text, 'parse_mode'=>'MarkDown', 'reply_markup'=>$keyboard]);
            $processed++;
            if(isset($res->ok) && $res->ok){ $success++; $q['success'] = (int)($q['success'] ?? 0)+1; }
            else { $failed++; $q['failed'] = (int)($q['failed'] ?? 0)+1; $q['last_error'] = isset($res->description) ? (string)$res->description : 'unknown_error'; }
            $offset++; $q['offset'] = $offset;
        }
        $q['status'] = $offset >= count($ids) ? 'done' : 'running';
        if($q['status'] === 'done') $q['finished_ts'] = time();
        @file_put_contents($file, json_encode($q, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT), LOCK_EX);
        $release();
        return ['ok'=>true, 'status'=>$q['status'], 'processed'=>$processed, 'success'=>$success, 'failed'=>$failed];
    }
}

if(!function_exists('bot_daily_reset_all')){
    function bot_daily_reset_all(){
        $pdo = bot_daily_pdo();
        $ok = false;
        if($pdo){
            bot_daily_install_schema();
            try{ $pdo->exec('UPDATE bot_daily_rewards SET next_claim_ts=0'); $ok = true; }
            catch(Throwable $e){ error_log('BOT daily reset failed: '.$e->getMessage()); }
        }
        // Also clear legacy per-user timers so no old route/cache can block users after reset.
        if(function_exists('bot_data_scandir') && function_exists('bot_data_get_json')){
            foreach(bot_data_scandir('melat') as $file){
                if($file === '.' || $file === '..' || !preg_match('/^(\d+)\.json$/', (string)$file, $m)) continue;
                $u = bot_data_get_json('melat/'.$file, []);
                if(!is_array($u)) continue;
                $u['time-day'] = '0';
                $u['daily_next_ts'] = 0;
                if(function_exists('saveJson')) saveJson('melat/'.$file, $u);
                elseif(function_exists('bot_data_put_json')) bot_data_put_json('melat/'.$file, $u);
            }
            $ok = true;
        }
        return $ok;
    }
}

if(!function_exists('bot_daily_runtime_router')){
    function bot_daily_runtime_router(){
        global $message, $msg, $data, $data_id, $chatID, $userID, $Tc, $isAdmin, $user, $step, $Button_Home, $Button_Panel, $Button_back_panel, $dok1, $doktxt1, $money, $icmoney, $msg_id;
        if(!isset($Tc) || (string)$Tc !== 'private') return false;

        $txt = trim((string)($msg ?? ''));
        $dailyPanelLabels = ['جمع اوری الماس', '💎 جمع اوری الماس', '🎁 جایزه روزانه', 'جایزه روزانه']; // فقط برای سازگاری با کیبوردهای قدیمی؛ در منوی جدید نمایش داده نمی‌شود
        $freeLabels = [];
        if(isset($dok1) && trim((string)$dok1) !== '') $freeLabels[] = trim((string)$dok1);
        $freeLabels = array_unique(array_merge($freeLabels, ['💎 دریافت رایگان','دریافت الماس رایگان','دریافت رایگان','الماس رایگان']));

        // Admin panel.
        if(isset($message) && $isAdmin && in_array($txt, ['🎁 الماس روزانه','🎁الماس روزانه','الماس روزانه'], true)){
            if(is_array($user)){ $user['step']='none'; if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user); }
            SM($chatID, bot_daily_admin_text(), 'html', null, bot_daily_admin_keyboard());
            return true;
        }

        if(isset($message) && $isAdmin && isset($step) && preg_match('/^dailyadm_(amount|days)$/', (string)$step, $m)){
            if(function_exists('bot_is_menu_back_text') && bot_is_menu_back_text($txt)){
                $user['step']='none'; if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user);
                SM($chatID, bot_daily_admin_text(), 'html', null, bot_daily_admin_keyboard());
                return true;
            }
            $n = bot_daily_clean_int($txt);
            if($n <= 0){ SM($chatID, '❌ فقط عدد مثبت وارد کنید.', 'html', null, $Button_back_panel); return true; }
            if($m[1] === 'amount') bot_daily_save_settings(['amount'=>$n]);
            else bot_daily_save_settings(['interval_days'=>$n]);
            $user['step']='none'; if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user);
            SM($chatID, '✅ تنظیمات الماس روزانه ذخیره شد.', 'html', null, bot_daily_admin_keyboard());
            return true;
        }

        if(isset($data) && $isAdmin && preg_match('/^dailyadm_/', (string)$data)){
            $s = bot_daily_settings();
            if((string)$data === 'dailyadm_toggle_enabled'){
                $s['enabled'] = ((string)$s['enabled'] === '✅فعال') ? '❌غیر فعال' : '✅فعال';
                bot_daily_save_settings($s);
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'وضعیت تغییر کرد', 'show_alert'=>false]);
                bot('editMessageText', ['chat_id'=>$chatID, 'message_id'=>$msg_id, 'text'=>bot_daily_admin_text(), 'parse_mode'=>'HTML', 'reply_markup'=>bot_daily_admin_keyboard()]);
                return true;
            }
            if((string)$data === 'dailyadm_toggle_channel'){
                $s['channel_button_enabled'] = ((string)$s['channel_button_enabled'] === '✅فعال') ? '❌غیر فعال' : '✅فعال';
                bot_daily_save_settings($s);
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'دکمه کانال تغییر کرد', 'show_alert'=>false]);
                bot('editMessageText', ['chat_id'=>$chatID, 'message_id'=>$msg_id, 'text'=>bot_daily_admin_text(), 'parse_mode'=>'HTML', 'reply_markup'=>bot_daily_admin_keyboard()]);
                return true;
            }
            if(in_array((string)$data, ['dailyadm_toggle_notify','dailyadm_run_notify_now','dailyadm_set_notify_text'], true)){
                // Compatibility for old inline buttons already sent before this update.
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'طبق نسخه جدید، کرون الماس روزانه حذف شده است.', 'show_alert'=>true]);
                bot('editMessageText', ['chat_id'=>$chatID, 'message_id'=>$msg_id, 'text'=>bot_daily_admin_text(), 'parse_mode'=>'HTML', 'reply_markup'=>bot_daily_admin_keyboard()]);
                return true;
            }
            if((string)$data === 'dailyadm_set_amount' || (string)$data === 'dailyadm_set_days'){
                $field = ((string)$data === 'dailyadm_set_amount') ? 'amount' : 'days';
                $user['step'] = 'dailyadm_'.$field;
                if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user);
                $prompt = $field === 'amount' ? '💎 تعداد الماس روزانه را ارسال کنید.' : '📆 فاصله دریافت را به روز ارسال کنید. مثال: 3 یعنی هر ۳ روز یکبار.';
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'عدد را ارسال کنید', 'show_alert'=>false]);
                SM($chatID, $prompt, 'html', null, $Button_back_panel);
                return true;
            }
            if((string)$data === 'dailyadm_reset_all'){
                bot_daily_reset_all();
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'زمان دریافت کاربران ریست شد', 'show_alert'=>true]);
                bot('editMessageText', ['chat_id'=>$chatID, 'message_id'=>$msg_id, 'text'=>bot_daily_admin_text(), 'parse_mode'=>'HTML', 'reply_markup'=>bot_daily_admin_keyboard()]);
                return true;
            }
        }

        // User opens the daily reward entry from the main user panel.
        if(isset($message) && in_array($txt, $dailyPanelLabels, true)){
            if(is_array($user)){ $user['step']='none'; if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user); }
            $s = bot_daily_settings();
            $body = "💎 **جمع اوری الماس**\n\n".
                "از دکمه‌های زیر استفاده کنید:\n".
                "• الماس روزانه: دریافت ".number_format((int)$s['amount'])." ".($money ?? 'الماس')." هر ".(int)$s['interval_days']." روز\n".
                "• کانال سفارشات: ورود مستقیم به کانال سفارشات";
            SM($chatID, $body, 'MarkDown', null, bot_daily_user_keyboard());
            return true;
        }

        // Keep the old free-diamond entry compatible; it now shows the same two inline buttons.
        if(isset($message) && in_array($txt, $freeLabels, true)){
            if(is_array($user)){ $user['step']='none'; if(function_exists('saveJson')) saveJson('melat/'.$userID.'.json', $user); }
            $body = isset($doktxt1) && trim((string)$doktxt1) !== '' ? (string)$doktxt1 : "💎 به بخش دریافت الماس خوش آمدید.\nاز دکمه‌های زیر استفاده کنید.";
            $body = bot_daily_apply_text($body, ['MONEY'=>$money ?? 'الماس', 'ICMONEY'=>$icmoney ?? '💎']);
            SM($chatID, $body, 'html', null, bot_daily_user_keyboard());
            return true;
        }

        // User claims daily reward.
        if(isset($data) && (string)$data === 'dailygiftt'){
            $res = bot_daily_claim($userID);
            if(!empty($res['ok'])){
                $s = bot_daily_settings();
                $msgText = bot_daily_apply_text((string)$s['success_text'], [
                    'AMOUNT'=>number_format((int)$res['amount']),
                    'BALANCE'=>number_format((int)$res['after']),
                    'DAYS'=>(string)$res['interval_days'],
                    'MONEY'=>$money ?? 'الماس',
                    'ICMONEY'=>$icmoney ?? '💎',
                ]);
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>$msgText, 'show_alert'=>true]);
                return true;
            }
            if(($res['error'] ?? '') === 'cooldown'){
                $s = bot_daily_settings();
                $msgText = bot_daily_apply_text((string)$s['cooldown_text'], [
                    'REMAINING'=>bot_daily_remaining_text($res['remaining'] ?? 0),
                    'DAYS'=>(string)$s['interval_days'],
                    'MONEY'=>$money ?? 'الماس',
                    'ICMONEY'=>$icmoney ?? '💎',
                ]);
                bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>$msgText, 'show_alert'=>true]);
                return true;
            }
            bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>$res['message'] ?? '❌ خطا در دریافت الماس روزانه.', 'show_alert'=>true]);
            return true;
        }

        if(isset($data) && (string)$data === 'daily_order_channel_missing'){
            bot('answercallbackquery', ['callback_query_id'=>$data_id, 'text'=>'کانال سفارشات هنوز با یوزرنیم عمومی در پنل تنظیم نشده است.', 'show_alert'=>true]);
            return true;
        }

        return false;
    }
}
