<?php

declare(strict_types=1);

namespace Australcode\Rewards\Infrastructure\Logging;

use Psr\Log\AbstractLogger;

defined( 'ABSPATH' ) || exit;

/**
 * PSR-3 logger writing daily files to uploads/acrwd-logs/.
 *
 * Structured, append-only. Lazily resolves the uploads dir so the class can be
 * constructed in tests without a live WP filesystem (log() no-ops if the dir
 * cannot be created).
 */
final class FileLogger extends AbstractLogger {

	private ?string $log_dir = null;

	/**
	 * @param mixed                $level
	 * @param string|\Stringable   $message
	 * @param array<string,mixed>  $context
	 */
	public function log( $level, string|\Stringable $message, array $context = array() ): void {
		$dir = $this->log_dir();
		if ( null === $dir ) {
			return;
		}

		$line = sprintf(
			"[%s] %s: %s %s\n",
			gmdate( 'Y-m-d H:i:s' ),
			strtoupper( (string) $level ),
			(string) $message,
			$context ? (string) wp_json_encode( $context ) : ''
		);

		$file = $dir . '/' . gmdate( 'Y-m-d' ) . '.log';
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- internal append-only log; WP_Filesystem is overkill on a hot path.
		file_put_contents( $file, $line, FILE_APPEND | LOCK_EX );
	}

	private function log_dir(): ?string {
		if ( null !== $this->log_dir ) {
			return $this->log_dir;
		}
		if ( ! function_exists( 'wp_upload_dir' ) ) {
			return null;
		}
		$uploads = wp_upload_dir();
		$dir     = trailingslashit( $uploads['basedir'] ) . 'acrwd-logs';
		if ( ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) {
			return null;
		}
		$this->log_dir = $dir;
		return $this->log_dir;
	}
}
