<?php

namespace AIPT\Api\BulkGenerator\Desc\Core;

class OutputValidator {

	public static function validate( string $content, string $type, array $options = array() ): ValidationResult {
		$result = new ValidationResult();

		if ( empty( trim( $content ) ) ) {
			$result->errors[] = 'Content is empty';
			return $result;
		}

		switch ( $type ) {
			case 'short_description':
			case 'description':
				self::validateDescription( $content, $result );
				break;

			case 'tags':
				$maxCount = $options['max_tags_count'] ?? (int) get_option( 'aipt_max_tags_count', 5 );
				self::validateTags( $content, $maxCount, $result );
				break;
		}

		$result->isValid = empty( $result->errors );
		return $result;
	}

	private static function validateDescription( string $content, ValidationResult $result ): void {
		if ( preg_match( '/```|^\s*#/m', $content ) ) {
			$result->warnings[] = 'Content contains Markdown formatting';
		}

		if ( preg_match( '/<script|<iframe|javascript:/i', $content ) ) {
			$result->errors[] = 'Content contains potentially unsafe HTML';
		}
	}

	private static function validateTags( string $content, int $maxCount, ValidationResult $result ): void {
		$tags = array_filter( array_map( 'trim', explode( ',', $content ) ) );

		if ( empty( $tags ) ) {
			$result->errors[] = 'No valid tags found';
			return;
		}

		if ( count( $tags ) > $maxCount * 2 ) {
			$result->warnings[] = 'Too many tags generated';
		}

		foreach ( $tags as $tag ) {
			if ( preg_match( '/[<>{}()\[\]\/\\\\]/', $tag ) ) {
				$result->warnings[] = "Tag contains invalid characters: {$tag}";
			}
			if ( strlen( $tag ) > 100 ) {
				$result->warnings[] = "Tag too long: {$tag}";
			}
		}
	}

	public static function sanitize( string $content, string $type ): string {
		if ( $type === 'tags' ) {
			return self::sanitizeTags( $content );
		}

		return self::sanitizeDescription( $content );
	}

	private static function sanitizeDescription( string $content ): string {
		$content = preg_replace( '/^\s*```[a-zA-Z]*\s*\n?/', '', $content );
		$content = preg_replace( '/\n?\s*```\s*$/', '', $content );

		$allowedTags = self::getAllowedHtmlTags();

		if ( ! empty( $allowedTags ) ) {
			$content = wp_kses( $content, $allowedTags );
		} else {
			$content = wp_kses_post( $content );
		}

		$content = preg_replace( '/(<\/(p|div|h[1-6]|ul|ol|li|blockquote|table|tr)>)(?!\s*$)(?!\s*\n)/i', "$1\n", $content );
		$content = preg_replace( '/\n{3,}/', "\n\n", $content );

		return trim( $content );
	}

	private static function getAllowedHtmlTags(): array {
		$setting = get_option( 'aipt_allowed_html_tags', array() );

		if ( is_string( $setting ) ) {
			if ( empty( $setting ) ) {
				return array();
			}
			$tagNames = array_filter( array_map( 'trim', explode( ',', $setting ) ) );
		} elseif ( is_array( $setting ) ) {
			$tagNames = $setting;
		} else {
			return array();
		}

		if ( empty( $tagNames ) ) {
			return array();
		}

		$allowedTags = array();
		$defaultAttrs = array(
			'class' => true,
			'id'    => true,
			'style' => true,
		);

		foreach ( $tagNames as $tag ) {
			$tag = preg_replace( '/[^a-z0-9]/', '', strtolower( $tag ) );

			if ( empty( $tag ) ) {
				continue;
			}

			switch ( $tag ) {
				case 'a':
					$allowedTags['a'] = array_merge( $defaultAttrs, array(
						'href'   => true,
						'title'  => true,
						'target' => true,
						'rel'    => true,
					) );
					break;
				case 'img':
					$allowedTags['img'] = array_merge( $defaultAttrs, array(
						'src'      => true,
						'alt'      => true,
						'width'    => true,
						'height'   => true,
						'srcset'   => true,
						'sizes'    => true,
						'loading'  => true,
						'decoding' => true,
						'title'    => true,
					) );
					break;
				default:
					$allowedTags[ $tag ] = $defaultAttrs;
					break;
			}
		}

		return $allowedTags;
	}

	private static function sanitizeTags( string $content ): string {
		$content = trim( $content );
		$content = trim( $content, '[]' );
		$content = str_replace( array( '"', "'" ), '', $content );
		$content = wp_strip_all_tags( $content );

		$tags      = array_filter( array_map( 'trim', explode( ',', $content ) ) );
		$cleanTags = array();

		foreach ( $tags as $tag ) {
			$tag = preg_replace( '/[#*_`<>{}()\[\]\/\\\\]/', '', $tag );
			$tag = preg_replace( '/^tags:\s*/i', '', $tag );
			$tag = trim( $tag );

			if ( ! empty( $tag ) && strlen( $tag ) <= 100 ) {
				$cleanTags[] = $tag;
			}
		}

		return implode( ', ', $cleanTags );
	}

	public static function truncateToLimit( string $content, string $type, array $options = array() ): string {
		if ( $type === 'tags' ) {
			$maxCount = $options['max_tags_count'] ?? (int) get_option( 'aipt_max_tags_count', 5 );
			$tags     = array_filter( array_map( 'trim', explode( ',', $content ) ) );
			$tags     = array_slice( $tags, 0, $maxCount );
			return implode( ', ', $tags );
		}

		return $content;
	}
}

class ValidationResult {
	public bool $isValid   = false;
	public array $errors   = array();
	public array $warnings = array();
}
