<?php

namespace PloverCRM\Common;

use Monolog\Logger as MonologLogger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;

/**
 * Base Logger
 * 
 * Base class for all module loggers with Monolog integration
 */
abstract class BaseLogger
{
    /**
     * @var MonologLogger
     */
    protected $logger;

    /**
     * @var string Log directory path
     */
    protected $logDir;

    /**
     * @var string Channel name
     */
    protected $channelName;

    /**
     * @var array Structured activity metadata
     */
    protected $activityConfig = [];

    /**
     * Constructor
     *
     * @param string $channelName Logger channel name
     * @param string $logDirName Log directory name
     * @param string $logFilePrefix Log file prefix
     * @param array $activityConfig Structured activity config
     */
    public function __construct($channelName, $logDirName, $logFilePrefix, array $activityConfig = [])
    {
        $this->channelName = $channelName;
        $this->activityConfig = $activityConfig;

        // Get WordPress uploads directory
        $upload_dir = wp_upload_dir();
        $this->logDir = $upload_dir['basedir'] . '/plover-crm-logs/' . $logDirName;

        // Create log directory if it doesn't exist
        if (!file_exists($this->logDir)) {
            wp_mkdir_p($this->logDir);
        }

        // Initialize Monolog logger
        $this->initializeLogger($logFilePrefix);
    }

    /**
     * Initialize Monolog logger
     *
     * @param string $logFilePrefix Log file prefix
     */
    private function initializeLogger($logFilePrefix): void
    {
        try {
            // Create logger instance
            $this->logger = new MonologLogger($this->channelName);

            // Generate log file name with date
            $logFileName = $logFilePrefix . '-' . date('Y-m-d') . '.log';
            $logFilePath = $this->logDir . '/' . $logFileName;

            // Create stream handler
            $handler = new StreamHandler($logFilePath, MonologLogger::DEBUG);

            // Set JSON formatter for reliable parsing
            $formatter = new JsonFormatter();
            $handler->setFormatter($formatter);

            // Add handler to logger
            $this->logger->pushHandler($handler);

            // Add task ID to all log entries for grouping
            $this->logger->pushProcessor(function ($record) {
                $record['extra']['task_id'] = $this->getTaskId();
                return $record;
            });
        } catch (\Exception $e) {
            // Fallback: log to error_log if Monolog fails
            error_log("Failed to initialize logger for {$this->channelName}: " . $e->getMessage());
        }
    }

    /**
     * Get or generate task ID for log grouping
     *
     * @return string
     */
    private function getTaskId(): string
    {
        static $taskId = null;

        if ($taskId === null) {
            $taskId = 'task_' . uniqid() . '_' . time();
        }

        return $taskId;
    }

    /**
     * Check if logger is available
     *
     * @return bool
     */
    protected function isLoggerAvailable(): bool
    {
        return $this->logger !== null;
    }

    /**
     * Log info message
     *
     * @param string $message
     * @param array $context
     */
    protected function logInfo($message, array $context = []): void
    {
        $this->writeLog('info', $message, $context);
    }

    /**
     * Log warning message
     *
     * @param string $message
     * @param array $context
     */
    protected function logWarning($message, array $context = []): void
    {
        $this->writeLog('warning', $message, $context);
    }

    /**
     * Log error message
     *
     * @param string $message
     * @param array $context
     */
    protected function logError($message, array $context = []): void
    {
        $this->writeLog('error', $message, $context);
    }

    /**
     * Log debug message
     *
     * @param string $message
     * @param array $context
     */
    protected function logDebug($message, array $context = []): void
    {
        $this->writeLog('debug', $message, $context);
    }

    /**
     * Write to both raw log files and the structured activity stream.
     */
    private function writeLog(string $level, $message, array $context = []): void
    {
        $taskId = $this->getTaskId();
        $activityOverride = [];

        if (isset($context['_activity']) && is_array($context['_activity'])) {
            $activityOverride = $context['_activity'];
            unset($context['_activity']);
        }

        if ($this->isLoggerAvailable()) {
            $method = $level;
            $this->logger->{$method}($message, $context);
        }

        $activityConfig = array_merge($this->activityConfig, $activityOverride);
        if (($activityConfig['persist'] ?? true) !== true) {
            return;
        }

        ActivityEventManager::record([
            'module' => $activityConfig['module'] ?? 'system',
            'feature' => $activityConfig['feature'] ?? 'general',
            'channel' => $this->channelName,
            'level' => $level,
            'status' => $activityConfig['status'] ?? null,
            'summary' => is_string($message) ? $message : 'Activity recorded',
            'details' => $context,
            'task_id' => $taskId,
        ]);
    }
}
