<?php
declare( strict_types=1 );

namespace WPDesk\Logger;

use Monolog\Handler\HandlerInterface;
use Monolog\Logger;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Processor\PsrLogMessageProcessor;
use Monolog\Processor\UidProcessor;
use Psr\Log\LogLevel;
use WPDesk\Logger\WC\WooCommerceHandler;

final class SimpleLoggerFactory implements LoggerFactory {

	/**
	 * @var array{
	 *   level?: string,
	 * }
	 */
	private $options;

	/** @var string */
	private $channel;

	/** @var Logger */
	private $logger;

	/**
	 * Valid options are:
	 *   * level (default debug): Default logging level
	 */
	public function __construct( string $channel, $options = null ) {
		$this->channel = $channel;

		if ( $options instanceof Settings ) {
			$options = $options->to_array();
		}

		$this->options = array_merge(
			[
				'level'        => LogLevel::DEBUG,
			],
			$options
		);
	}

	public function getLogger( $name = null ): Logger {
		if ( $this->logger ) {
			return $this->logger;
		}

		$this->logger = new Logger(
			$this->channel,
			[],
			[ new PsrLogMessageProcessor( null, true ), new UidProcessor() ],
			wp_timezone()
		);

		if ( \function_exists( 'wc_get_logger' ) && \did_action( 'woocommerce_init' ) ) {
			$this->create_wc_handler();
		} else {
			\add_action( 'woocommerce_init', [ $this, 'create_wc_handler' ] );
		}

		// In the worst-case scenario, when WC logs are not available (yet, or at all),
		// fallback to WP logs, but only when enabled.
		if ( empty( $this->logger->getHandlers() ) && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
			$this->set_handler(
				$this->logger,
				new ErrorLogHandler( ErrorLogHandler::OPERATING_SYSTEM, $this->options['level'] );
			);
		}

		return $this->logger;
	}

	/**
	 * @internal
	 */
	public function set_wc_handler(): void {
		$this->set_handler(
			$this->logger,
			new WooCommerceHandler( \wc_get_logger(), $this->channel )
		);
	}

	private function set_handler( Logger $logger, HandlerInterface $handler ): void {
		// Purposefully replace all existing handlers.
		$logger->setHandlers( [ $handler ] );
	}
}