<?php

/**
 * Cron Logging System
 * Tracks cron job execution and performance
 */

class CronLog
{
    private static $logId = null;
    private static $startTime = null;
    private static $startMemory = null;

    /**
     * Start logging a cron job
     * @param string $cronType Type of cron job (main, reminder, etc.)
     * @return int Log ID
     */
    public static function start($cronType = 'main')
    {
        self::$startTime = microtime(true);
        self::$startMemory = memory_get_usage();
        
        $log = ORM::for_table('tbl_cron_logs')->create();
        $log->cron_type = $cronType;
        $log->started_at = date('Y-m-d H:i:s');
        $log->status = 'running';
        $log->save();
        
        self::$logId = $log->id();
        return self::$logId;
    }

    /**
     * Update log with current statistics
     * @param array $stats Statistics array
     */
    public static function updateStats($stats = [])
    {
        if (!self::$logId) return;
        
        $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId);
        if (!$log) return;
        
        foreach ($stats as $key => $value) {
            if (property_exists($log, $key)) {
                $log->$key = $value;
            }
        }
        
        $log->save();
    }

    /**
     * Increment a counter
     * @param string $field Field to increment
     * @param int $amount Amount to increment by
     */
    public static function increment($field, $amount = 1)
    {
        if (!self::$logId) return;
        
        $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId);
        if (!$log) return;
        
        if (property_exists($log, $field)) {
            $log->$field = $log->$field + $amount;
            $log->save();
        }
    }

    /**
     * Complete the cron job successfully
     * @param array $finalStats Final statistics
     */
    public static function complete($finalStats = [])
    {
        if (!self::$logId) return;
        
        $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId);
        if (!$log) return;
        
        $log->finished_at = date('Y-m-d H:i:s');
        $log->status = 'completed';
        
        // Calculate execution time
        if (self::$startTime) {
            $log->execution_time = round(microtime(true) - self::$startTime, 3);
        }
        
        // Calculate memory usage
        if (self::$startMemory) {
            $currentMemory = memory_get_usage();
            $peakMemory = memory_get_peak_usage();
            $log->memory_usage = self::formatBytes($peakMemory - self::$startMemory);
        }
        
        // Update final stats
        foreach ($finalStats as $key => $value) {
            if (property_exists($log, $key)) {
                $log->$key = $value;
            }
        }
        
        $log->save();
        
        // Clean up old logs (keep last 1000 records)
        self::cleanup();
    }

    /**
     * Mark cron job as failed
     * @param string $errorMessage Error message
     * @param array $finalStats Final statistics
     */
    public static function fail($errorMessage, $finalStats = [])
    {
        if (!self::$logId) return;
        
        $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId);
        if (!$log) return;
        
        $log->finished_at = date('Y-m-d H:i:s');
        $log->status = 'failed';
        $log->error_message = $errorMessage;
        
        // Calculate execution time
        if (self::$startTime) {
            $log->execution_time = round(microtime(true) - self::$startTime, 3);
        }
        
        // Update final stats
        foreach ($finalStats as $key => $value) {
            if (property_exists($log, $key)) {
                $log->$key = $value;
            }
        }
        
        $log->save();
    }

    /**
     * Get recent cron logs
     * @param int $limit Number of records to return
     * @param string $cronType Filter by cron type
     * @return array
     */
    public static function getRecent($limit = 50, $cronType = null)
    {
        $query = ORM::for_table('tbl_cron_logs');
        
        if ($cronType) {
            $query->where('cron_type', $cronType);
        }
        
        return $query->order_by_desc('started_at')
                    ->limit($limit)
                    ->find_many();
    }

    /**
     * Get cron job statistics
     * @param int $days Number of days to look back
     * @return array
     */
    public static function getStats($days = 7)
    {
        $since = date('Y-m-d H:i:s', strtotime("-$days days"));
        
        $stats = ORM::for_table('tbl_cron_logs')
            ->where_gte('started_at', $since)
            ->find_many();
        
        $result = [
            'total_runs' => count($stats),
            'successful_runs' => 0,
            'failed_runs' => 0,
            'total_expired_users' => 0,
            'total_notifications_sent' => 0,
            'total_auto_renewals' => 0,
            'avg_execution_time' => 0,
            'last_run' => null,
            'last_success' => null,
            'last_failure' => null
        ];
        
        $totalExecutionTime = 0;
        $executionCount = 0;
        
        foreach ($stats as $log) {
            if ($log->status == 'completed') {
                $result['successful_runs']++;
                $result['last_success'] = $log->finished_at;
            } elseif ($log->status == 'failed') {
                $result['failed_runs']++;
                $result['last_failure'] = $log->finished_at;
            }
            
            $result['total_expired_users'] += $log->expired_users_processed;
            $result['total_notifications_sent'] += $log->notifications_sent;
            $result['total_auto_renewals'] += $log->auto_renewals_successful;
            
            if ($log->execution_time) {
                $totalExecutionTime += $log->execution_time;
                $executionCount++;
            }
            
            if (!$result['last_run'] || $log->started_at > $result['last_run']) {
                $result['last_run'] = $log->started_at;
            }
        }
        
        if ($executionCount > 0) {
            $result['avg_execution_time'] = round($totalExecutionTime / $executionCount, 3);
        }
        
        return $result;
    }

    /**
     * Clean up old logs (keep last 1000 records)
     */
    private static function cleanup()
    {
        $count = ORM::for_table('tbl_cron_logs')->count();
        
        if ($count > 1000) {
            $logsToDelete = ORM::for_table('tbl_cron_logs')
                ->order_by_asc('started_at')
                ->limit($count - 1000)
                ->find_many();
            
            foreach ($logsToDelete as $log) {
                $log->delete();
            }
        }
    }

    /**
     * Format bytes to human readable format
     * @param int $bytes
     * @return string
     */
    private static function formatBytes($bytes)
    {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        
        $bytes /= pow(1024, $pow);
        
        return round($bytes, 2) . ' ' . $units[$pow];
    }

    /**
     * Check if cron is running (has a running log in last 5 minutes)
     * @return bool
     */
    public static function isRunning()
    {
        $fiveMinutesAgo = date('Y-m-d H:i:s', strtotime('-5 minutes'));
        
        $runningLog = ORM::for_table('tbl_cron_logs')
            ->where('status', 'running')
            ->where_gte('started_at', $fiveMinutesAgo)
            ->find_one();
        
        return $runningLog ? true : false;
    }

    /**
     * Get the last successful cron run
     * @return object|null
     */
    public static function getLastSuccess()
    {
        return ORM::for_table('tbl_cron_logs')
            ->where('status', 'completed')
            ->order_by_desc('finished_at')
            ->find_one();
    }
}
