<?php
/**
 * Accordion — manual items (title + content + image) or posts query (loop-like).
 *
 * @package AuraBuilder
 */

declare(strict_types=1);

namespace AuraBuilder\Widgets\Basic;


use AuraBuilder\Support\Json;
use AuraBuilder\Document\Node;
use AuraBuilder\Widgets\WidgetBase;
use WP_Query;

final class AccordionWidget extends WidgetBase {

	public function get_type(): string {
		return 'accordion';
	}

	public function get_title(): string {
		return 'Acordeão';
	}

	public function get_icon(): string {
		return 'accordion';
	}

	public function get_defaults(): array {
		return array(
			'source'         => 'manual', // manual | posts
			// Manual items: JSON list of {title, content, image}
			'items'          => Json::encode(
				array(
					array(
						'title'   => 'Pergunta 1',
						'content' => 'Resposta da primeira pergunta.',
						'image'   => '',
					),
					array(
						'title'   => 'Pergunta 2',
						'content' => 'Resposta da segunda pergunta.',
						'image'   => '',
					),
				)
			),
			'open_first'     => '1',
			'multiple'       => '0', // allow several items open
			'icon_style'     => 'plus', // plus | chevron
			'image_position'  => 'top', // top | left | right (inside body)
			'object_fit'      => 'cover',
			'object_position' => '50% 50%',
			// Posts query (like loop grid).
			'posts_per_page' => '6',
			'query_source'   => 'post',
			'orderby'        => 'date',
			'order'          => 'DESC',
			'category'       => '',
			'include_ids'    => '',
			'exclude_ids'    => '',
			'show_image'     => '1',
			'show_excerpt'   => '1',
			'excerpt_length' => '40',
			'image_size'     => 'medium_large',
		);
	}

	public function sanitize_settings( array $settings ): array {
		$flag = static function ( $v, string $d = '1' ): string {
			if ( $v === null || $v === '' ) {
				return $d;
			}
			return ( $v === true || $v === 1 || $v === '1' || $v === 'true' || $v === 'yes' ) ? '1' : '0';
		};

		$source = sanitize_key( (string) ( $settings['source'] ?? 'manual' ) );
		if ( ! in_array( $source, array( 'manual', 'posts' ), true ) ) {
			$source = 'manual';
		}

		$orderby = sanitize_key( (string) ( $settings['orderby'] ?? 'date' ) );
		$allowed = array( 'date', 'title', 'menu_order', 'rand', 'modified', 'ID' );
		if ( ! in_array( $orderby, $allowed, true ) ) {
			$orderby = 'date';
		}
		$order = strtoupper( (string) ( $settings['order'] ?? 'DESC' ) );
		if ( ! in_array( $order, array( 'ASC', 'DESC' ), true ) ) {
			$order = 'DESC';
		}

		$query_source = sanitize_key( (string) ( $settings['query_source'] ?? 'post' ) );
		if ( $query_source === '' ) {
			$query_source = 'post';
		}

		$image_size = sanitize_key( (string) ( $settings['image_size'] ?? 'medium_large' ) );
		if ( $image_size === '' ) {
			$image_size = 'medium_large';
		}

		$icon = sanitize_key( (string) ( $settings['icon_style'] ?? 'plus' ) );
		if ( ! in_array( $icon, array( 'plus', 'chevron' ), true ) ) {
			$icon = 'plus';
		}
		$img_pos = sanitize_key( (string) ( $settings['image_position'] ?? 'top' ) );
		if ( ! in_array( $img_pos, array( 'top', 'left', 'right' ), true ) ) {
			$img_pos = 'top';
		}
		$fit = sanitize_key( (string) ( $settings['object_fit'] ?? 'cover' ) );
		if ( ! in_array( $fit, array( 'cover', 'contain', 'fill', 'none' ), true ) ) {
			$fit = 'cover';
		}
		$obj_pos = self::sanitize_object_position( $settings['object_position'] ?? '50% 50%' );

		return array(
			'source'         => $source,
			'items'          => $this->sanitize_items( (string) ( $settings['items'] ?? '' ) ),
			'open_first'     => $flag( $settings['open_first'] ?? null, '1' ),
			'multiple'       => $flag( $settings['multiple'] ?? null, '0' ),
			'icon_style'     => $icon,
			'image_position' => $img_pos,
			'object_fit'     => $fit,
			'object_position'=> $obj_pos,
			'posts_per_page' => (string) max( 1, min( 48, (int) ( $settings['posts_per_page'] ?? 6 ) ) ),
			'query_source'   => $query_source,
			'orderby'        => $orderby,
			'order'          => $order,
			'category'       => sanitize_text_field( (string) ( $settings['category'] ?? '' ) ),
			'include_ids'    => $this->sanitize_id_list( (string) ( $settings['include_ids'] ?? '' ) ),
			'exclude_ids'    => $this->sanitize_id_list( (string) ( $settings['exclude_ids'] ?? '' ) ),
			'show_image'     => $flag( $settings['show_image'] ?? null, '1' ),
			'show_excerpt'   => $flag( $settings['show_excerpt'] ?? null, '1' ),
			'excerpt_length' => (string) max( 5, min( 120, (int) ( $settings['excerpt_length'] ?? 40 ) ) ),
			'image_size'     => $image_size,
		);
	}

	private function sanitize_id_list( string $raw ): string {
		$parts = preg_split( '/[\s,;]+/', $raw ) ?: array();
		$ids   = array();
		foreach ( $parts as $p ) {
			$n = (int) $p;
			if ( $n > 0 ) {
				$ids[] = (string) $n;
			}
		}
		return implode( ',', array_unique( $ids ) );
	}

	/**
	 * Accept JSON items or legacy "Title|Content" lines.
	 */
	private function sanitize_items( string $raw ): string {
		$items = self::parse_items( $raw );
		$clean = array();
		foreach ( $items as $it ) {
			$clean[] = array(
				'title'   => sanitize_text_field( (string) ( $it['title'] ?? '' ) ),
				'content' => sanitize_textarea_field( (string) ( $it['content'] ?? '' ) ),
				'image'   => esc_url_raw( (string) ( $it['image'] ?? '' ) ),
			);
		}
		// Cap size.
		if ( count( $clean ) > 40 ) {
			$clean = array_slice( $clean, 0, 40 );
		}
		$json = Json::encode( $clean );
		return is_string( $json ) ? $json : '[]';
	}

	/**
	 * @return list<array{title:string,content:string,image:string}>
	 */
	public static function parse_items( string $raw ): array {
		$raw = trim( $raw );
		if ( $raw === '' ) {
			return array();
		}
		// Repair stripslashes damage on \uXXXX (matru00edcula, ud83dudccd…).
		$raw = Json::repair_stripped_unicode( $raw );

		// JSON array?
		if ( str_starts_with( $raw, '[' ) ) {
			$decoded = json_decode( $raw, true );
			if ( is_array( $decoded ) ) {
				$out = array();
				foreach ( $decoded as $row ) {
					if ( is_string( $row ) ) {
						// "Title|Content" string inside JSON.
						$parts = explode( '|', $row, 2 );
						$out[] = array(
							'title'   => Json::repair_stripped_unicode( trim( $parts[0] ) ),
							'content' => Json::repair_stripped_unicode( trim( $parts[1] ?? '' ) ),
							'image'   => '',
						);
						continue;
					}
					if ( ! is_array( $row ) ) {
						continue;
					}
					$out[] = array(
						'title'   => Json::repair_stripped_unicode( (string) ( $row['title'] ?? '' ) ),
						'content' => Json::repair_stripped_unicode( (string) ( $row['content'] ?? '' ) ),
						'image'   => (string) ( $row['image'] ?? $row['url'] ?? '' ),
					);
				}
				return $out;
			}
		}

		// Legacy pipe lines (Title|Content or Title|Content|ImageURL).
		$out   = array();
		$lines = preg_split( '/\r\n|\r|\n/', $raw ) ?: array();
		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( $line === '' ) {
				continue;
			}
			$parts = explode( '|', $line );
			$out[] = array(
				'title'   => Json::repair_stripped_unicode( trim( (string) ( $parts[0] ?? '' ) ) ),
				'content' => Json::repair_stripped_unicode( trim( (string) ( $parts[1] ?? '' ) ) ),
				'image'   => trim( (string) ( $parts[2] ?? '' ) ),
			);
		}
		return $out;
	}

	/**
	 * @return list<array{title:string,content:string,image:string}>
	 */
	private function items_from_posts( array $s ): array {
		$post_type = sanitize_key( (string) ( $s['query_source'] ?? 'post' ) );
		// Allow post, page, or both.
		if ( $post_type === 'any' || $post_type === 'post_page' ) {
			$post_type_arg = array( 'post', 'page' );
		} elseif ( $post_type === 'page' ) {
			$post_type_arg = 'page';
		} else {
			$post_type_arg = $post_type !== '' ? $post_type : 'post';
		}

		$ppp     = max( 1, min( 48, (int) ( $s['posts_per_page'] ?? 6 ) ) );
		$orderby = (string) ( $s['orderby'] ?? 'date' );
		$order   = (string) ( $s['order'] ?? 'DESC' );

		$args = array(
			'post_type'              => $post_type_arg,
			'post_status'            => 'publish',
			'posts_per_page'         => $ppp,
			'orderby'                => $orderby,
			'order'                  => $order,
			'ignore_sticky_posts'    => true,
			'no_found_rows'          => true,
			'update_post_meta_cache' => true,
			'update_post_term_cache' => false,
		);

		// Category only applies to posts (not pages).
		$is_page_only = $post_type_arg === 'page';
		$cat          = trim( (string) ( $s['category'] ?? '' ) );
		if ( $cat !== '' && ! $is_page_only ) {
			if ( ctype_digit( $cat ) ) {
				$args['cat'] = (int) $cat;
			} else {
				$args['category_name'] = sanitize_title( $cat );
			}
		}

		$include = array_values( array_filter( array_map( 'intval', explode( ',', (string) ( $s['include_ids'] ?? '' ) ) ) ) );
		if ( $include ) {
			$args['post__in'] = $include;
			$args['orderby']  = 'post__in';
		}
		$exclude = array_values( array_filter( array_map( 'intval', explode( ',', (string) ( $s['exclude_ids'] ?? '' ) ) ) ) );
		if ( $exclude ) {
			$args['post__not_in'] = $exclude;
		}

		$items = array();
		try {
			$q = new WP_Query( $args );
		} catch ( \Throwable $e ) {
			return $items;
		}

		$show_img = ( $s['show_image'] ?? '1' ) === '1';
		$show_ex  = ( $s['show_excerpt'] ?? '1' ) === '1';
		$len      = max( 5, min( 120, (int) ( $s['excerpt_length'] ?? 40 ) ) );
		$size     = (string) ( $s['image_size'] ?? 'medium_large' );
		if ( $size === '' ) {
			$size = 'medium_large';
		}

		foreach ( $q->posts as $post ) {
			if ( ! $post instanceof \WP_Post ) {
				continue;
			}
			$title = get_the_title( $post );
			if ( $title === '' ) {
				$title = '#' . (string) $post->ID;
			}

			// Excerpt without relying on global $post filters that may fatal.
			$raw = '';
			if ( $show_ex ) {
				$raw = (string) $post->post_excerpt;
				if ( $raw === '' ) {
					$raw = wp_strip_all_tags( (string) $post->post_content );
					$raw = preg_replace( '/\s+/', ' ', $raw ) ?? $raw;
				} else {
					$raw = wp_strip_all_tags( $raw );
				}
				$words = preg_split( '/\s+/u', trim( $raw ) ) ?: array();
				if ( count( $words ) > $len ) {
					$raw = implode( ' ', array_slice( $words, 0, $len ) ) . '…';
				}
			} else {
				$raw = wp_strip_all_tags( (string) $post->post_content );
				$raw = preg_replace( '/\s+/', ' ', $raw ) ?? $raw;
				if ( function_exists( 'mb_substr' ) ) {
					if ( mb_strlen( $raw ) > 400 ) {
						$raw = mb_substr( $raw, 0, 400 ) . '…';
					}
				} elseif ( strlen( $raw ) > 400 ) {
					$raw = substr( $raw, 0, 400 ) . '…';
				}
			}

			$image = '';
			if ( $show_img && has_post_thumbnail( $post ) ) {
				$thumb = get_the_post_thumbnail_url( $post, $size );
				if ( ! $thumb ) {
					$thumb = get_the_post_thumbnail_url( $post, 'large' );
				}
				if ( ! $thumb ) {
					$thumb = get_the_post_thumbnail_url( $post, 'full' );
				}
				$image = is_string( $thumb ) ? $thumb : '';
			}

			$items[] = array(
				'title'   => $title,
				'content' => $raw,
				'image'   => $image,
			);
		}
		wp_reset_postdata();
		return $items;
	}

	public function render( Node $node, array $context = array() ): string {
		$s      = $node->settings;
		$source = (string) ( $s['source'] ?? 'manual' );
		try {
			$items = $source === 'posts'
				? $this->items_from_posts( $s )
				: self::parse_items( (string) ( $s['items'] ?? '' ) );
		} catch ( \Throwable $e ) {
			return ! empty( $context['editor'] )
				? '<div class="ab-accordion ab-empty">Acordeão (posts): erro na consulta. Verifique tipo/categoria.</div>'
				: '';
		}

		// Drop empty titles.
		$items = array_values(
			array_filter(
				$items,
				static function ( $it ) {
					return trim( (string) ( $it['title'] ?? '' ) ) !== '';
				}
			)
		);

		if ( ! $items ) {
			return ! empty( $context['editor'] )
				? '<div class="ab-accordion ab-empty">Acordeão — adicione itens ou ative posts</div>'
				: '';
		}

		$open_first = ( $s['open_first'] ?? '1' ) === '1';
		$multiple   = ( $s['multiple'] ?? '0' ) === '1' ? '1' : '0';
		$icon_style = (string) ( $s['icon_style'] ?? 'plus' );
		$img_pos    = (string) ( $s['image_position'] ?? 'top' );
		$icon_char  = $icon_style === 'chevron' ? '▾' : '+';
		$fit        = esc_attr( (string) ( $s['object_fit'] ?? 'cover' ) );
		$obj_pos    = esc_attr( self::sanitize_object_position( $s['object_position'] ?? '50% 50%' ) );
		$media_vars = '--ab-acc-fit:' . $fit . ';--ab-acc-pos:' . $obj_pos . ';';

		$html = '<div class="ab-accordion ab-accordion--img-' . esc_attr( $img_pos )
			. ' ab-accordion--icon-' . esc_attr( $icon_style )
			. '" data-ab-accordion="1" data-multiple="' . $multiple . '" style="' . esc_attr( $media_vars ) . '">';
		foreach ( $items as $i => $item ) {
			$open    = $open_first && $i === 0 ? ' is-open' : '';
			$title   = (string) ( $item['title'] ?? '' );
			$content = (string) ( $item['content'] ?? '' );
			$image   = (string) ( $item['image'] ?? '' );

			$html .= '<div class="ab-accordion__item' . $open . '">';
			$html .= '<button type="button" class="ab-accordion__head">'
				. '<span class="ab-accordion__title">' . esc_html( $title ) . '</span>'
				. '<span class="ab-accordion__icon" aria-hidden="true">' . esc_html( $icon_char ) . '</span>'
				. '</button>';
			$html .= '<div class="ab-accordion__body">';
			if ( $image !== '' ) {
				$html .= '<figure class="ab-accordion__media"><img src="' . esc_url( $image ) . '" alt="' . esc_attr( $title ) . '" loading="lazy" style="object-fit:' . $fit . ';object-position:' . $obj_pos . '"/></figure>';
			}
			if ( $content !== '' ) {
				$html .= '<div class="ab-accordion__content">';
				// Allow simple paragraphs from newlines.
				$paras = preg_split( '/\n\n+/', $content ) ?: array( $content );
				foreach ( $paras as $p ) {
					$p = trim( $p );
					if ( $p !== '' ) {
						$html .= '<p class="ab-accordion__text">' . esc_html( $p ) . '</p>';
					}
				}
				$html .= '</div>';
			}
			$html .= '</div></div>';
		}
		$html .= '</div>';
		return $html;
	}
}
