<?php
/**
 * This file is part of the Wisewand WordPress plugin.
 *
 * @package Wisewand
 * @since 1.0.0
 * @license GPL-2.0-or-later
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
namespace Wisewand\Utils;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_error_log -- error_log() is only used within WP_DEBUG conditionals for debugging

class Content_Cleaner {

	/**
	 * Clean and process Wisewand content for WordPress
	 */
	public static function clean_content( $content, $options = array() ) {
		$default_options = array(
			'remove_h1'              => true,
			'fix_headings'           => true,
			'clean_empty_paragraphs' => true,
			'optimize_images'        => true,
			'preserve_audio_players' => true,
			'fix_encoded_html'       => true,
		);

		$options = array_merge( $default_options, $options );

		// Log original content for debugging
		if ( WP_DEBUG ) {
			error_log( 'Wisewand Content Cleaning - Original length: ' . strlen( $content ) );
		}
		if ( WP_DEBUG ) {
			error_log( 'Wisewand Content Cleaning - Original H1 count: ' . substr_count( strtolower( $content ), '<h1' ) );
		}

		// Fix encoded HTML tags FIRST (convert &lt;img&gt; back to <img>)
		if ( $options['fix_encoded_html'] ) {
			$content = self::fix_encoded_html_tags( $content );
		}

		// Remove H1 tags COMPLETELY (tags + content)
		if ( $options['remove_h1'] ) {
			$content = self::remove_h1_tags( $content );
		}

		// Fix heading hierarchy (convert remaining headings)
		if ( $options['fix_headings'] ) {
			$content = self::fix_heading_hierarchy( $content );
		}

		// Clean empty paragraphs
		if ( $options['clean_empty_paragraphs'] ) {
			$content = self::clean_empty_paragraphs( $content );
		}

		// Optimize image attributes
		if ( $options['optimize_images'] ) {
			$content = self::optimize_image_attributes( $content );
		}

		// Preserve existing audio players
		if ( $options['preserve_audio_players'] ) {
			$content = self::preserve_audio_players( $content );
		}

		// Log final content for debugging
		if ( WP_DEBUG ) {
			error_log( 'Wisewand Content Cleaning - Final length: ' . strlen( $content ) );
		}
		if ( WP_DEBUG ) {
			error_log( 'Wisewand Content Cleaning - Final H1 count: ' . substr_count( strtolower( $content ), '<h1' ) );
		}

		return $content;
	}

	/**
	 * Fix encoded HTML tags (convert &lt;img&gt; back to <img>)
	 */
	public static function fix_encoded_html_tags( $content ) {
		// Fix encoded img tags
		$content = preg_replace( '/&lt;img([^&]*?)\/&gt;/i', '<img$1/>', $content );
		$content = preg_replace( '/&lt;img([^&]*?)&gt;/i', '<img$1>', $content );

		// Fix other common encoded tags
		$content = str_replace( array( '&lt;', '&gt;' ), array( '<', '>' ), $content );

		// Fix quotes in attributes
		$content = preg_replace( '/(\w+)=(["\'])([^"\']*?)\2/', '$1="$3"', $content );

		return $content;
	}

	/**
	 * Remove H1 tags AND their content completely (since WordPress post title handles this)
	 */
	public static function remove_h1_tags( $content ) {
		// Log original content for debugging
		$original_h1_count = substr_count( strtolower( $content ), '<h1' );

		// Remove H1 tags and ALL content inside them (including the text)
		// This regex handles multiline H1 content and various attributes
		$content = preg_replace( '/<h1[^>]*>.*?<\/h1>/is', '', $content );

		// Also handle self-closing or malformed H1 tags
		$content = preg_replace( '/<h1[^>]*\/?>/i', '', $content );

		// Remove any orphaned closing h1 tags
		$content = preg_replace( '/<\/h1>/i', '', $content );

		// Clean up any multiple line breaks left behind
		$content = preg_replace( '/\n\s*\n\s*\n+/', "\n\n", $content );

		// Remove empty paragraphs that might be left after H1 removal
		$content = preg_replace( '/<p[^>]*>[\s\n\r]*<\/p>/i', '', $content );

		// Clean up any leading/trailing whitespace
		$content = trim( $content );

		// Log the cleaning results for debugging
		$new_h1_count = substr_count( strtolower( $content ), '<h1' );
		if ( WP_DEBUG ) {
			error_log( "Wisewand H1 Removal: {$original_h1_count} H1 tags found, {$new_h1_count} remaining after cleaning" );
		}

		return $content;
	}

	/**
	 * Fix heading hierarchy by shifting all headings down one level
	 */
	public static function fix_heading_hierarchy( $content ) {
		// Convert H6 to H6 (keep as is - deepest level)
		// Convert H5 to H6
		$content = preg_replace( '/<h5([^>]*)>/i', '<h6$1>', $content );
		$content = preg_replace( '/<\/h5>/i', '</h6>', $content );

		// Convert H4 to H5
		$content = preg_replace( '/<h4([^>]*)>/i', '<h5$1>', $content );
		$content = preg_replace( '/<\/h4>/i', '</h5>', $content );

		// Convert H3 to H4
		$content = preg_replace( '/<h3([^>]*)>/i', '<h4$1>', $content );
		$content = preg_replace( '/<\/h3>/i', '</h4>', $content );

		// Convert H2 to H3
		$content = preg_replace( '/<h2([^>]*)>/i', '<h3$1>', $content );
		$content = preg_replace( '/<\/h2>/i', '</h3>', $content );

		// Convert any remaining H1 to H2
		$content = preg_replace( '/<h1([^>]*)>/i', '<h2$1>', $content );
		$content = preg_replace( '/<\/h1>/i', '</h2>', $content );

		return $content;
	}

	/**
	 * Remove empty paragraphs and clean up spacing
	 */
	public static function clean_empty_paragraphs( $content ) {
		// Remove empty paragraphs
		$content = preg_replace( '/<p[^>]*>[\s]*<\/p>/i', '', $content );

		// Remove paragraphs with only whitespace or &nbsp;
		$content = preg_replace( '/<p[^>]*>[\s&nbsp;]*<\/p>/i', '', $content );

		// Clean up multiple consecutive line breaks
		$content = preg_replace( '/(<\/p>\s*){2,}/', '</p>' . "\n", $content );

		return $content;
	}

	/**
	 * Optimize image attributes for better performance and accessibility
	 */
	public static function optimize_image_attributes( $content ) {
		return preg_replace_callback(
			'/<img([^>]+)>/i',
			function ( $matches ) {
				$img_tag    = $matches[0];
				$attributes = $matches[1];

				// Add loading="lazy" if not present
				if ( strpos( $attributes, 'loading=' ) === false ) {
					$attributes .= ' loading="lazy"';
				}

				// Add decoding="async" if not present
				if ( strpos( $attributes, 'decoding=' ) === false ) {
					$attributes .= ' decoding="async"';
				}

				// Ensure alt attribute exists (for accessibility)
				if ( strpos( $attributes, 'alt=' ) === false ) {
					$attributes .= ' alt=""';
				}

				return '<img' . $attributes . '>';
			},
			$content
		);
	}

	/**
	 * Preserve existing audio players (don't duplicate)
	 */
	public static function preserve_audio_players( $content ) {
		// Mark existing audio players to avoid duplication
		return preg_replace( '/<audio([^>]*)>/i', '<audio$1 data-wisewand-preserved="true">', $content );
	}

	/**
	 * Generate HTML audio player with correct MIME type detection
	 *
	 * @param string   $audio_url     URL of the audio file.
	 * @param int|null $attachment_id Optional WordPress attachment ID for MIME detection.
	 * @return string Audio player HTML.
	 */
	public static function generate_audio_player( $audio_url, $attachment_id = null ) {
		// Detect MIME type from attachment or URL (3-tier fallback)
		$mime_type = 'audio/mpeg'; // Default fallback

		// Tier 1: Try to get MIME type from attachment metadata (most reliable)
		if ( $attachment_id ) {
			$attachment_mime = get_post_mime_type( $attachment_id );
			if ( $attachment_mime && strpos( $attachment_mime, 'audio/' ) === 0 ) {
				$mime_type = $attachment_mime;
			}
		}

		// Tier 2: If no attachment or MIME type not detected, try URL extension
		if ( 'audio/mpeg' === $mime_type ) {
			$ext = strtolower( pathinfo( parse_url( $audio_url, PHP_URL_PATH ), PATHINFO_EXTENSION ) );

			$mime_map = array(
				'mp3'  => 'audio/mpeg',
				'wav'  => 'audio/wav',
				'ogg'  => 'audio/ogg',
				'oga'  => 'audio/ogg',
				'm4a'  => 'audio/mp4',
				'aac'  => 'audio/aac',
				'flac' => 'audio/flac',
				'opus' => 'audio/opus',
			);

			if ( isset( $mime_map[ $ext ] ) ) {
				$mime_type = $mime_map[ $ext ];
			}
		}
		// Tier 3: Default 'audio/mpeg' used if neither tier 1 nor 2 succeeds

		$audio_html  = '<div class="wisewand-audio-player" style="margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 8px; border-left: 4px solid #2271b1;">';
		$audio_html .= '<p style="margin: 0 0 10px 0; font-weight: 600; color: #1d2327;">🎧 ' . esc_html__( 'Listen to this article', 'wisewand-ai-content-writer-seo-content-generator' ) . '</p>';
		$audio_html .= '<audio controls preload="metadata" style="width: 100%; max-width: 500px;">';
		$audio_html .= '<source src="' . esc_url( $audio_url ) . '" type="' . esc_attr( $mime_type ) . '">';
		$audio_html .= '<p>' . esc_html__( 'Your browser does not support the audio element.', 'wisewand-ai-content-writer-seo-content-generator' ) . '</p>';
		$audio_html .= '</audio>';
		$audio_html .= '</div>';

		return $audio_html;
	}

	/**
	 * Allow WiseWand media tags (audio, video iframes, wrappers, JSON-LD) in KSES filtering.
	 *
	 * Single source of truth for WiseWand-imported content KSES rules. Use as a
	 * wp_kses_allowed_html filter callback or call directly to modify an allowed
	 * tags array. Protects iframe YouTube/Vimeo embeds (with their responsive
	 * style wrapper), audio players, and Schema.org JSON-LD blocks during the
	 * secondary wp_update_post() calls that run after the initial insert.
	 *
	 * @param array  $allowed_tags Allowed HTML tags and attributes.
	 * @param string $context      Context for which to retrieve tags (e.g., 'post').
	 * @return array Modified allowed tags.
	 */
	public static function allow_audio_kses( $allowed_tags, $context ) {
		if ( 'post' !== $context ) {
			return $allowed_tags;
		}

		$allowed_tags['source'] = array(
			'src'  => true,
			'type' => true,
		);

		if ( ! isset( $allowed_tags['audio'] ) ) {
			$allowed_tags['audio'] = array();
		}

		$allowed_tags['audio'] = array_merge(
			$allowed_tags['audio'],
			array(
				'controls'                => true,
				'preload'                 => true,
				'style'                   => true,
				'data-wisewand-preserved' => true,
			)
		);

		// <iframe>: YouTube/Vimeo video embeds injected by the API
		// (use_video / video_position). WordPress's default 'post' KSES
		// allowlist strips this tag entirely, which would remove all embedded
		// videos from imported articles.
		$allowed_tags['iframe'] = array(
			'src'             => true,
			'width'           => true,
			'height'          => true,
			'style'           => true,
			'title'           => true,
			'allow'           => true,
			'allowfullscreen' => true,
			'frameborder'     => true,
			'referrerpolicy'  => true,
			'loading'         => true,
			'sandbox'         => true,
			'name'            => true,
			'class'           => true,
			'id'              => true,
		);

		// Preserve the 'style' attribute on common block wrappers. The iframe
		// ships wrapped in <div style="position: relative; padding-bottom:
		// 56.25%; ..."> to achieve a responsive 16:9 aspect ratio. The inline
		// <figure style="..."> wrappers around inline images rely on the same
		// attribute. Without this, the video container collapses to 0 height.
		foreach ( array( 'div', 'figure', 'p', 'span' ) as $wrapper ) {
			if ( ! isset( $allowed_tags[ $wrapper ] ) ) {
				$allowed_tags[ $wrapper ] = array();
			}

			$allowed_tags[ $wrapper ] = array_merge(
				$allowed_tags[ $wrapper ],
				array(
					'style' => true,
					'class' => true,
					'id'    => true,
				)
			);
		}

		// <script type="application/ld+json">: Schema.org structured data.
		// Only the 'type' attribute is whitelisted — arbitrary <script> tags
		// without a type cannot pass through KSES.
		$allowed_tags['script'] = array(
			'type' => true,
		);

		return $allowed_tags;
	}

	/**
	 * Extract title from H1 for use as post title
	 */
	public static function extract_h1_title( $content ) {
		preg_match( '/<h1[^>]*>(.*?)<\/h1>/is', $content, $matches );
		if ( ! empty( $matches[1] ) ) {
			return wp_strip_all_tags( $matches[1] );
		}
		return '';
	}

	/**
	 * Remove specific HTML elements while preserving content
	 */
	public static function remove_html_element( $content, $element ) {
		$pattern = "/<{$element}[^>]*>(.*?)<\/{$element}>/is";
		return preg_replace( $pattern, '$1', $content );
	}

	/**
	 * Insert content at the beginning of post content
	 */
	public static function prepend_to_content( $existing_content, $new_content ) {
		// Add proper spacing between new content and existing content
		return $new_content . "\n\n" . $existing_content;
	}

	/**
	 * Clean and format content for specific post types
	 */
	public static function format_for_post_type( $content, $post_type ) {
		switch ( $post_type ) {
			case 'page':
				// For pages, keep more formal structure
				$content = self::clean_content(
					$content,
					array(
						'remove_h1'    => true,
						'fix_headings' => false, // Keep original heading structure for pages
					)
				);
				break;

			case 'post':
			default:
				// For posts, optimize for blog reading
				$content = self::clean_content(
					$content,
					array(
						'remove_h1'    => true,
						'fix_headings' => false, // Keep original structure (Wisewand API provides correct H2/H3)
					)
				);
				break;
		}

		return $content;
	}
}
