<?php
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Template variables are scoped when required inside the block render callback.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

require_once dirname( __DIR__, 3 ) . '/includes/block-css-generator.php';
require_once dirname( __DIR__, 3 ) . '/includes/render-helpers/heading-content.php';

// ─── Tag & identity ───────────────────────────────────────────────────────────

$tag_name     = isset( $attributes['tagName'] ) ? strtolower( (string) $attributes['tagName'] ) : 'h2';
$allowed_tags = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'span' ];
$tag_name     = tag_escape( in_array( $tag_name, $allowed_tags, true ) ? $tag_name : 'h2' );

$anchor       = isset( $attributes['anchor'] ) ? sanitize_title( $attributes['anchor'] ) : '';
$unique_class = isset( $attributes['uniqueClass'] ) ? sanitize_html_class( $attributes['uniqueClass'] ) : '';
if ( empty( $unique_class ) ) {
	$unique_class = sanitize_html_class( 'axb-' . wp_unique_id() );
}

// ─── Wrapper attributes ───────────────────────────────────────────────────────
// `has-icon` flips the heading into the icon-beside-text flex layout (see
// shared-frontend.scss). Without an icon it stays a normal heading so its inline
// content (<strong>, <em>) flows naturally.

$icon_present = ! empty( $attributes['iconSvg'] );
$extra_attrs  = [
	'class' => trim( 'axcelersblocks-heading__text ' . $unique_class . ( $icon_present ? ' has-icon' : '' ) ),
];
if ( $anchor ) {
	$extra_attrs['id'] = $anchor;
}
$wrapper_attrs = get_block_wrapper_attributes( $extra_attrs );

// ─── Link options (needed before CSS so is_linked context is correct) ─────────

$link_option  = $attributes['linkOption']  ?? 'none';
$custom_link  = isset( $attributes['customLink'] ) ? esc_url( $attributes['customLink'] ) : '';
$open_new_tab = ! empty( $attributes['openInNewTab'] );
$target_attr  = $open_new_tab ? ' target="_blank"' : '';
$link_title   = isset( $attributes['linkTitle'] ) ? sanitize_text_field( $attributes['linkTitle'] ) : '';
$aria_label   = isset( $attributes['ariaLabel'] ) ? sanitize_text_field( $attributes['ariaLabel'] ) : '';
$rel_tokens   = [];

if ( $open_new_tab ) {
	$rel_tokens[] = 'noopener';
	$rel_tokens[] = 'noreferrer';
}
if ( ! empty( $attributes['relNoFollow'] ) ) {
	$rel_tokens[] = 'nofollow';
}
if ( ! empty( $attributes['relSponsored'] ) ) {
	$rel_tokens[] = 'sponsored';
}
if ( ! empty( $attributes['relUgc'] ) ) {
	$rel_tokens[] = 'ugc';
}

$rel_value      = implode( ' ', array_unique( array_filter( $rel_tokens ) ) );
$rel_attr       = $rel_value ? ' rel="' . esc_attr( $rel_value ) . '"' : '';
$link_title_attr = $link_title ? ' title="' . esc_attr( $link_title ) . '"' : '';
$aria_label_attr = $aria_label ? ' aria-label="' . esc_attr( $aria_label ) . '"' : '';
$is_linked    = $custom_link !== '' || ( ! empty( $attributes['dynamicTag'] ) && $link_option !== 'none' );

// ─── CSS generation & collection ──────────────────────────────────────────────

$devices = axcelersblocks_get_responsive_devices();

// column-gap is purely the icon↔text gap (only meaningful in the .has-icon flex
// layout). Without an icon there's no flex, so don't emit it at all.
$main_attributes = $attributes;
if ( ! $icon_present ) {
	unset( $main_attributes['columnGap'] );
}
$styles_css = axcelersblocks_generate_block_styles( $unique_class, $devices, $main_attributes, [ 'is_linked' => $is_linked ] );

// Content tab: the text span (.axcelersblocks-heading__content) carries its own
// full style set, stored under the `contentStyles` object and emitted to the span
// via the generator's element_suffix.
$content_styles = ( isset( $attributes['contentStyles'] ) && is_array( $attributes['contentStyles'] ) ) ? $attributes['contentStyles'] : [];
$content_css    = axcelersblocks_generate_block_styles(
	$unique_class,
	$devices,
	$content_styles,
	[ 'element_suffix' => ' .axcelersblocks-heading__content', 'has_icon' => false, 'is_linked' => false ]
);

axcelersblocks_collect_block_styles( $unique_class, $block, array_merge( $styles_css, $content_css ) );

// ─── Icon ─────────────────────────────────────────────────────────────────────

$icon_loc  = $attributes['iconLocation'] ?? 'before';
$icon_html = '';
if ( ! empty( $attributes['iconSvg'] ) ) {
	$icon_svg  = wp_kses( $attributes['iconSvg'], axcelersblocks_get_allowed_svg_html() );
	$icon_html = $icon_svg ? sprintf( '<span class="icon">%s</span>', $icon_svg ) : '';
}

// ─── Content assembly ─────────────────────────────────────────────────────────

$text_html   = '';
$link_href   = '';
$author_href = '';
$term_href   = '';

if ( ! empty( $attributes['dynamicTag'] ) ) {
	$resolved    = axcelersblocks_heading_resolve_dynamic( $attributes );
	$text_html   = $resolved['text'];
	$link_href   = $resolved['link_href'];
	$author_href = $resolved['author_href'];
	$term_href   = $resolved['term_href'];

} elseif ( ! empty( $attributes['content'] ) ) {
	$text_html = wp_kses_post( $attributes['content'] );

} else {
	$required  = array_key_exists( 'required', $attributes ) ? (bool) $attributes['required'] : true;
	$text_html = $required ? esc_html__( '(No content provided)', 'axcelersblocks' ) : '';
}

// Wrap the text in its own .__content element so it stays a single flex item when
// the icon layout is active (inline <strong>/<em> never split into flex items).
$content_html = '' !== $text_html
	? '<span class="axcelersblocks-heading__content">' . $text_html . '</span>'
	: '';

$final_output = $icon_loc === 'before'
	? $icon_html . $content_html
	: $content_html . $icon_html;

// ─── Link resolution ──────────────────────────────────────────────────────────

$resolved_link = '';
if ( $custom_link ) {
	$resolved_link = $custom_link;
} elseif ( ! empty( $attributes['dynamicTag'] ) && $link_option !== 'none' ) {
	$selected_tag = $attributes['selectedTag'] ?? 'post_title';
	if ( $selected_tag === 'post_author' && $link_option === 'author' && $author_href ) {
		$resolved_link = esc_url( $author_href );
	} elseif ( $link_option === 'post' && $link_href ) {
		$resolved_link = $selected_tag === 'comments_url'
			? esc_url( $link_href . '#comments' )
			: esc_url( $link_href );
	} elseif ( $link_option === 'term' && $term_href ) {
		$resolved_link = esc_url( $term_href );
	}
}

// ─── Output ───────────────────────────────────────────────────────────────────

$heading_html = sprintf(
	'<%1$s %2$s>%3$s</%1$s>',
	esc_attr( $tag_name ),
	$wrapper_attrs, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- get_block_wrapper_attributes() returns escaped output.
	wp_kses( $final_output, axcelersblocks_get_allowed_svg_html() )
);

if ( $resolved_link ) {
	$link_class = sanitize_html_class( $unique_class ) . '-link';
	printf(
		'<a href="%1$s" class="%2$s"%3$s%4$s%5$s%6$s>%7$s</a>',
		esc_url( $resolved_link ),
		esc_attr( $link_class ),
		$target_attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Hardcoded safe attribute fragment.
		$rel_attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Hardcoded safe attribute fragment.
		$link_title_attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped safe attribute fragment.
		$aria_label_attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped safe attribute fragment.
		$heading_html // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	);
} else {
	echo $heading_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
// phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
