<?php
/**
 * Validates generated snippet artifacts before they can go live.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Snippet_Validator {
	const MAX_FILES = 40;
	const MAX_FILE_BYTES = 102400;

	private $forbidden_php = array(
		'eval',
		'shell_exec',
		'exec',
		'passthru',
		'system',
		'proc_open',
		'popen',
		'assert',
		'curl_exec',
		'base64_decode',
		'file_put_contents',
		'fwrite',
		'unlink',
		'rmdir',
	);

	public function validate( $snippet ) {
		$files = isset( $snippet['files'] ) && is_array( $snippet['files'] ) ? $snippet['files'] : array();
		$type  = isset( $snippet['type'] ) ? Niwa_AI_Template_Library_Types::normalize_snippet_type( $snippet['type'] ) : Niwa_AI_Template_Library_Types::TYPE_SHORTCODE;

		if ( empty( $files ) ) {
			return new WP_Error( 'snippet_no_files', __( 'Snippet has no files.', 'niwa-ai' ) );
		}
		if ( count( $files ) > self::MAX_FILES ) {
			return new WP_Error( 'snippet_too_many_files', __( 'Snippet has too many files.', 'niwa-ai' ) );
		}

		$seen = array();
		$has_template = false;
		$has_main = false;
		$has_widget = false;
		foreach ( $files as $file ) {
			$name    = isset( $file['name'] ) ? (string) $file['name'] : '';
			$content = isset( $file['content'] ) ? (string) $file['content'] : '';
			$check   = $this->validate_file( $name, $content );
			if ( is_wp_error( $check ) ) {
				return $check;
			}
			$lower = strtolower( $name );
			if ( isset( $seen[ $lower ] ) ) {
				return new WP_Error( 'snippet_duplicate_file', sprintf( __( 'Duplicate snippet file: %s', 'niwa-ai' ), $name ) );
			}
			$seen[ $lower ] = true;
			if ( 'template.html' === $lower ) {
				$has_template = true;
				if ( false !== strpos( $content, 'data-niwa-template-unresolved="1"' ) || false !== strpos( $content, "data-niwa-template-unresolved='1'" ) ) {
					return new WP_Error( 'snippet_unresolved_template', __( 'This template was not built by Niwa yet. Ask Niwa in chat to build it for a target Elementor page, or provide concrete shortcode instructions before publishing.', 'niwa-ai' ) );
				}
			}
			if ( 'main.php' === $lower ) {
				$has_main = true;
			}
			if ( 'widget.php' === $lower ) {
				$has_widget = true;
			}
		}

		if ( Niwa_AI_Template_Library_Types::TYPE_WORDPRESS_ADMIN_SNIPPET === $type && ! $has_main ) {
			return new WP_Error( 'snippet_missing_main', __( 'Admin snippets require main.php.', 'niwa-ai' ) );
		}
		if ( Niwa_AI_Template_Library_Types::TYPE_ELEMENTOR_WIDGET === $type && ( ! $has_main || ! $has_widget ) ) {
			return new WP_Error( 'snippet_missing_widget', __( 'Elementor widget snippets require main.php and widget.php.', 'niwa-ai' ) );
		}
		if ( ! in_array( $type, array( Niwa_AI_Template_Library_Types::TYPE_WORDPRESS_ADMIN_SNIPPET, Niwa_AI_Template_Library_Types::TYPE_ELEMENTOR_WIDGET ), true ) && ! $has_template ) {
			return new WP_Error( 'snippet_missing_template', __( 'Frontend snippets require template.html.', 'niwa-ai' ) );
		}

		return array(
			'success' => true,
			'message' => __( 'Snippet validation passed.', 'niwa-ai' ),
		);
	}

	private function validate_file( $name, $content ) {
		$name = (string) $name;
		if ( '' === $name || $name !== sanitize_file_name( $name ) || false !== strpos( $name, '..' ) || false !== strpos( $name, '/' ) || false !== strpos( $name, '\\' ) ) {
			return new WP_Error( 'snippet_bad_filename', sprintf( __( 'Invalid snippet filename: %s', 'niwa-ai' ), $name ) );
		}

		$ext = strtolower( pathinfo( $name, PATHINFO_EXTENSION ) );
		if ( ! in_array( $ext, array( 'php', 'css', 'js', 'html', 'json' ), true ) ) {
			return new WP_Error( 'snippet_bad_extension', sprintf( __( 'Unsupported snippet file extension: %s', 'niwa-ai' ), $name ) );
		}
		if ( strlen( (string) $content ) > self::MAX_FILE_BYTES ) {
			return new WP_Error( 'snippet_file_too_large', sprintf( __( 'Snippet file is too large: %s', 'niwa-ai' ), $name ) );
		}
		if ( 'php' === $ext ) {
			$lower = strtolower( (string) $content );
			foreach ( $this->forbidden_php as $fn ) {
				if ( preg_match( '/\b' . preg_quote( $fn, '/' ) . '\s*\(/', $lower ) ) {
					return new WP_Error( 'snippet_forbidden_php', sprintf( __( 'Forbidden PHP function in %1$s: %2$s', 'niwa-ai' ), $name, $fn ) );
				}
			}
		}

		return true;
	}
}
