<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Niwa_AI_LLM_Audit_Logger {
	const OPT_ENABLED = 'niwa_ai_llm_audit_enabled';
	const OPT_UNTIL   = 'niwa_ai_llm_audit_until';

	public static function is_enabled() {
		if ( defined( 'NIWA_AI_LLM_AUDIT_ENABLED' ) && NIWA_AI_LLM_AUDIT_ENABLED ) {
			return self::is_within_window();
		}

		$enabled = get_option( self::OPT_ENABLED, '0' );
		if ( true !== $enabled && '1' !== (string) $enabled && 'yes' !== strtolower( (string) $enabled ) ) {
			return false;
		}

		return self::is_within_window();
	}

	public static function new_event_id() {
		if ( function_exists( 'wp_generate_uuid4' ) ) {
			return wp_generate_uuid4();
		}

		return uniqid( 'niwa_llm_', true );
	}

	public static function record_event( $event, $context = array() ) {
		if ( ! self::is_enabled() ) {
			return;
		}

		if ( ! is_array( $context ) ) {
			$context = array( 'value' => $context );
		}

		$entry = array(
			'logged_at_utc' => gmdate( 'c' ),
			'logged_at_site' => function_exists( 'wp_date' ) ? wp_date( 'c' ) : date( 'c' ),
			'event' => sanitize_key( (string) $event ),
			'site_url' => function_exists( 'home_url' ) ? home_url( '/' ) : '',
			'plugin_version' => defined( 'NIWA_AI_VERSION' ) ? NIWA_AI_VERSION : '',
			'origin' => self::describe_origin(),
			'context' => self::sanitize_for_log( $context ),
		);

		$dir = self::get_log_dir();
		if ( '' === $dir ) {
			return;
		}

		if ( ! is_dir( $dir ) ) {
			wp_mkdir_p( $dir );
		}

		if ( ! is_dir( $dir ) || ! is_writable( $dir ) ) {
			return;
		}
		@chmod( $dir, 0700 );

		self::write_access_guards( $dir );

		$date = function_exists( 'wp_date' ) ? wp_date( 'Y-m-d' ) : gmdate( 'Y-m-d' );
		$file = trailingslashit( $dir ) . 'llm-audit-' . $date . '.jsonl';
		$line = wp_json_encode( $entry, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
		if ( ! is_string( $line ) || '' === $line ) {
			return;
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
		file_put_contents( $file, $line . "\n", FILE_APPEND | LOCK_EX );
		@chmod( $file, 0600 );
	}

	public static function get_log_dir() {
		$base = '';
		if ( defined( 'ABSPATH' ) ) {
			$base = dirname( untrailingslashit( ABSPATH ) );
		}

		if ( '' === $base || '.' === $base ) {
			$base = defined( 'WP_CONTENT_DIR' ) ? WP_CONTENT_DIR : '';
		}

		if ( '' === $base ) {
			return '';
		}

		return trailingslashit( $base ) . 'niwa-ai-llm-audit';
	}

	private static function is_within_window() {
		$until = intval( get_option( self::OPT_UNTIL, 0 ) );
		return $until <= 0 || time() <= $until;
	}

	private static function write_access_guards( $dir ) {
		$htaccess = trailingslashit( $dir ) . '.htaccess';
		if ( ! file_exists( $htaccess ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
			file_put_contents( $htaccess, "Require all denied\nDeny from all\n" );
			@chmod( $htaccess, 0600 );
		}

		$index = trailingslashit( $dir ) . 'index.php';
		if ( ! file_exists( $index ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
			file_put_contents( $index, "<?php\n// Silence is golden.\n" );
			@chmod( $index, 0600 );
		}
	}

	private static function describe_origin() {
		$trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 18 );
		$frames = array();
		$primary = array();
		$ignored_classes = array(
			'Niwa_AI_LLM_Audit_Logger',
			'Niwa_AI_OpenAI_Client',
			'Niwa_AI_Embedding_Client',
			'Niwa_AI_Agent_Stream_Reader',
		);

		foreach ( $trace as $frame ) {
			$class = isset( $frame['class'] ) ? (string) $frame['class'] : '';
			$function = isset( $frame['function'] ) ? (string) $frame['function'] : '';
			$file = isset( $frame['file'] ) ? self::short_path( (string) $frame['file'] ) : '';
			$line = isset( $frame['line'] ) ? intval( $frame['line'] ) : 0;

			if ( '' === $file && '' === $function ) {
				continue;
			}

			$record = array(
				'class' => $class,
				'function' => $function,
				'file' => $file,
				'line' => $line,
			);
			$frames[] = $record;

			if ( empty( $primary ) && ! in_array( $class, $ignored_classes, true ) ) {
				$primary = $record;
			}
		}

		return array(
			'primary' => $primary,
			'stack' => array_slice( $frames, 0, 12 ),
		);
	}

	private static function short_path( $path ) {
		$path = str_replace( '\\', '/', (string) $path );
		if ( defined( 'NIWA_AI_DIR' ) ) {
			$root = str_replace( '\\', '/', NIWA_AI_DIR );
			if ( 0 === strpos( $path, $root ) ) {
				return substr( $path, strlen( $root ) );
			}
		}

		if ( defined( 'ABSPATH' ) ) {
			$root = str_replace( '\\', '/', ABSPATH );
			if ( 0 === strpos( $path, $root ) ) {
				return substr( $path, strlen( $root ) );
			}
		}

		return $path;
	}

	private static function sanitize_for_log( $value ) {
		if ( is_array( $value ) ) {
			$out = array();
			foreach ( $value as $key => $item ) {
				$key_string = is_string( $key ) ? $key : (string) $key;
				if ( self::is_sensitive_key( $key_string ) ) {
					$out[ $key ] = '[redacted]';
					continue;
				}
				if ( in_array( $key_string, array( 'embedding', 'encrypted_content' ), true ) ) {
					$out[ $key ] = '[omitted:' . $key_string . ']';
					continue;
				}
				$out[ $key ] = self::sanitize_for_log( $item );
			}
			return $out;
		}

		if ( is_object( $value ) ) {
			return '[object:' . get_class( $value ) . ']';
		}

		if ( is_resource( $value ) ) {
			return '[resource]';
		}

		return $value;
	}

	private static function is_sensitive_key( $key ) {
		$key = strtolower( (string) $key );
		foreach ( array( 'authorization', 'api_key', 'access_token', 'refresh_token', 'codex_token', 'secret', 'password', 'bearer' ) as $needle ) {
			if ( false !== strpos( $key, $needle ) ) {
				return true;
			}
		}

		return false;
	}
}
