<?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/image-css.php';

// ─── Attributes ───────────────────────────────────────────────────────────────

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

$image_id          = isset( $attributes['imageId'] ) ? (int) $attributes['imageId'] : 0;
$image_url         = isset( $attributes['imageUrl'] ) ? esc_url_raw( $attributes['imageUrl'] ) : '';
$alt_external      = isset( $attributes['alt'] ) ? wp_strip_all_tags( $attributes['alt'] ) : '';
$render_inline_svg = ! empty( $attributes['renderInlineSvg'] );
$size_slug         = ! empty( $attributes['sizeSlug'] ) ? sanitize_key( $attributes['sizeSlug'] ) : 'full';

$dynamic_tag   = $attributes['dynamicTag']  ?? '';
$selected_tag  = $attributes['selectedTag'] ?? '';
$source_type   = $attributes['sourceType']  ?? 'current';
$post_id_attr  = isset( $attributes['postId'] ) ? (int) $attributes['postId'] : 0;
$post_type     = isset( $attributes['postType'] ) ? sanitize_key( $attributes['postType'] ) : 'post';
$source_entity = $attributes['sourceEntity'] ?? 'post';
$taxonomy      = isset( $attributes['taxonomy'] ) ? sanitize_key( $attributes['taxonomy'] ) : 'category';
$term_id_attr  = isset( $attributes['termId'] ) ? (int) $attributes['termId'] : 0;
$meta_key      = isset( $attributes['metaKey'] ) ? sanitize_key( $attributes['metaKey'] ) : '';
$acf_field     = isset( $attributes['acfField'] ) ? sanitize_text_field( $attributes['acfField'] ) : '';
$acf_scope     = $attributes['acfScope']    ?? 'entity';
$link_option   = $attributes['linkOption']  ?? 'none';
$custom_link   = isset( $attributes['customLink'] ) ? esc_url( $attributes['customLink'] ) : '';
$link_title    = isset( $attributes['linkTitle'] ) ? sanitize_text_field( $attributes['linkTitle'] ) : '';
$aria_label    = isset( $attributes['ariaLabel'] ) ? sanitize_text_field( $attributes['ariaLabel'] ) : '';
$rel_tokens    = [];

if ( $open_in_new ) {
	$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 ) . '"' : '';

// ─── Dynamic state ────────────────────────────────────────────────────────────

// True for any block that may produce dynamic image content (used for CSS link generation).
$has_dynamic = ! empty( $dynamic_tag ) || in_array( $selected_tag, [ 'featured_image', 'author_avatar', 'acf_field', 'post_meta', 'term_meta' ], true );

// True only when this specific block instance should resolve a featured image:
//   - an explicit dynamic tag that contains 'featured_image', OR
//   - the default mode where selectedTag = 'featured_image' with no override (no dynamic tag,
//     no library ID, no external URL) — mirrors the block's out-of-the-box frontend behaviour.
$is_featured_dynamic = (
	( ! empty( $dynamic_tag ) && strpos( $dynamic_tag, 'featured_image' ) !== false )
	|| ( $selected_tag === 'featured_image' && empty( $dynamic_tag ) && ! $image_id && empty( $image_url ) )
);

// Priority (LCP) images load eagerly with fetchpriority="high"; everything else
// respects the loading control, where 'auto' omits the attribute so WordPress can
// apply its own optimization (lazy vs. eager + fetchpriority), matching core output.
$priority   = ! empty( $attributes['priorityLoad'] );
$loading_v  = $priority ? 'eager' : ( $attributes['loading'] ?? 'auto' );
$decoding_v = $attributes['decoding'] ?? 'async';
$fetch_attr = $priority ? ' fetchpriority="high"' : '';
$loading_attr  = in_array( $loading_v,  [ 'lazy', 'eager' ], true ) ? ' loading="'  . esc_attr( $loading_v )  . '"' : '';
$decoding_attr = in_array( $decoding_v, [ 'async', 'sync' ],  true ) ? ' decoding="' . esc_attr( $decoding_v ) . '"' : '';

// Accurate `sizes`: when the block constrains the image to a fixed px width, the
// browser should not pick a srcset candidate larger than that. Computed from the
// most specific width/max-width set for the largest (desktop) breakpoint.
$custom_sizes = axcelersblocks_image_build_sizes( $attributes );

// ─── Wrapper attributes (<figure>) ───────────────────────────────────────────

$extra_attrs = [ 'class' => trim( 'axcelersblocks-image ' . $unique_class ) ];
if ( $anchor ) {
	$extra_attrs['id'] = $anchor;
}
$wrapper_attrs = get_block_wrapper_attributes( $extra_attrs );

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

$is_linked  = $custom_link !== '' || ( $has_dynamic && $link_option !== 'none' );
$devices    = axcelersblocks_get_responsive_devices();
$styles_css = axcelersblocks_generate_block_styles( $unique_class, $devices, $attributes, [ 'is_linked' => $is_linked ] );
$img_css    = axcelersblocks_image_generate_img_css( $unique_class, $devices, $attributes );
axcelersblocks_collect_block_styles( $unique_class, $block, array_merge( $styles_css, $img_css ) );

// ─── Responsive image source overrides ───────────────────────────────────────

$responsive_settings = get_option( 'axcelersblocks_responsive_settings' );
$responsive_settings = is_array( $responsive_settings ) ? $responsive_settings : [];
$tablet_width        = (string) ( $responsive_settings['devices']['tablet']['width'] ?? '1024' );
$mobile_width        = (string) ( $responsive_settings['devices']['mobile']['width'] ?? '768' );
$tablet_width        = (string) ( (int) $tablet_width );
$mobile_width        = (string) ( (int) $mobile_width );

$resolve_image_override = static function ( $raw, $size_slug ) {
	if ( ! is_array( $raw ) ) { return ''; }
	$override_id = isset( $raw['imageId'] ) ? (int) $raw['imageId'] : 0;
	if ( $override_id > 0 ) {
		$arr = wp_get_attachment_image_src( $override_id, $size_slug );
		$url = ! empty( $arr[0] ) ? $arr[0] : wp_get_attachment_url( $override_id );
		return $url ? esc_url_raw( $url ) : '';
	}
	if ( isset( $raw['imageUrl'] ) && is_string( $raw['imageUrl'] ) && $raw['imageUrl'] !== '' ) {
		return esc_url_raw( $raw['imageUrl'] );
	}
	return '';
};

$image_sources_raw   = isset( $attributes['imageSources'] ) && is_array( $attributes['imageSources'] ) ? $attributes['imageSources'] : [];
$tablet_override_url = $resolve_image_override( $image_sources_raw['tablet'] ?? [], $size_slug );
$mobile_override_url = $resolve_image_override( $image_sources_raw['mobile'] ?? [], $size_slug );

// ─── Image markup builder ─────────────────────────────────────────────────────

$contains_inline_svg      = false;
$contains_picture_element = false;
$contains_native_img      = false; // true when markup comes from wp_get_attachment_image() (trusted; skip wp_kses_post which would strip srcset/fetchpriority).

$build_image_markup = static function ( $src, $alt_text, $attachment_id = 0, $use_responsive = false ) use (
	$loading_v, $decoding_v, $loading_attr, $decoding_attr, $fetch_attr, $priority, $custom_sizes, $size_slug, $render_inline_svg,
	&$contains_inline_svg, &$contains_picture_element, &$contains_native_img,
	$tablet_override_url, $mobile_override_url, $tablet_width, $mobile_width
) {
	if ( '' === $src ) { return ''; }

	// Inline SVG path
	$svg_markup = '';
	if ( $render_inline_svg ) {
		if ( $attachment_id > 0 && function_exists( 'axcelersblocks_get_inline_svg_markup_from_attachment' ) ) {
			$svg_markup = axcelersblocks_get_inline_svg_markup_from_attachment( $attachment_id );
		}
		if ( '' === $svg_markup && function_exists( 'axcelersblocks_get_inline_svg_markup_from_url' ) ) {
			$svg_markup = axcelersblocks_get_inline_svg_markup_from_url( $src );
		}
	}
	if ( '' !== $svg_markup ) {
		$contains_inline_svg = true;
		$accessibility_attrs = '' !== $alt_text
			? ' role="img" aria-label="' . esc_attr( $alt_text ) . '"'
			: ' aria-hidden="true"';
		return sprintf( '<span class="axcelersblocks-image__svg"%1$s>%2$s</span>', $accessibility_attrs, $svg_markup );
	}

	// Attachment-backed images use wp_get_attachment_image() so WordPress generates
	// srcset, sizes, intrinsic width/height and applies loading optimization
	// (lazy / eager + fetchpriority for the LCP image) — exactly like the core image block.
	if ( $attachment_id > 0 ) {
		$attr = [ 'class' => 'axcelersblocks-image__img' ];
		if ( '' !== $alt_text )                                   { $attr['alt'] = $alt_text; }
		if ( in_array( $loading_v, [ 'lazy', 'eager' ], true ) )  { $attr['loading'] = $loading_v; }
		if ( in_array( $decoding_v, [ 'async', 'sync' ], true ) ) { $attr['decoding'] = $decoding_v; }
		if ( $priority )                                          { $attr['fetchpriority'] = 'high'; }
		if ( '' !== $custom_sizes )                               { $attr['sizes'] = $custom_sizes; }
		$img_tag = wp_get_attachment_image( $attachment_id, $size_slug, false, $attr );
		if ( '' !== $img_tag ) {
			$contains_native_img = true;
		} else {
			// Fallback to a plain tag if the attachment can't produce an image.
			$img_tag = sprintf(
				'<img class="axcelersblocks-image__img" src="%s" alt="%s"%s%s%s />',
				esc_url( $src ), esc_attr( $alt_text ), $loading_attr, $decoding_attr, $fetch_attr
			);
		}
	} else {
		// External URL / avatar — no attachment, so a plain tag (no srcset possible).
		$img_tag = sprintf(
			'<img class="axcelersblocks-image__img" src="%s" alt="%s"%s%s%s />',
			esc_url( $src ), esc_attr( $alt_text ), $loading_attr, $decoding_attr, $fetch_attr
		);
	}

	if ( ! $use_responsive ) { return $img_tag; }

	$has_tablet = '' !== $tablet_override_url;
	$has_mobile = '' !== $mobile_override_url;
	if ( ! $has_tablet && ! $has_mobile ) { return $img_tag; }

	$source_tags = '';
	if ( $has_mobile ) {
		$source_tags .= sprintf(
			'<source media="(max-width: %1$spx)" srcset="%2$s" />',
			esc_attr( $mobile_width ), esc_url( $mobile_override_url )
		);
	}
	if ( $has_tablet ) {
		$source_tags .= sprintf(
			'<source media="(max-width: %1$spx)" srcset="%2$s" />',
			esc_attr( $tablet_width ), esc_url( $tablet_override_url )
		);
	}

	$contains_picture_element = true;
	return '<picture>' . $source_tags . $img_tag . '</picture>';
};

// ─── Normalise value to { url, alt, id } ─────────────────────────────────────

$normalize_to_image = static function ( $value, $size_slug ) {
	$out = [ 'url' => '', 'alt' => '', 'id' => 0 ];
	if ( is_numeric( $value ) ) {
		$att_id = (int) $value;
		if ( $att_id > 0 ) {
			$src_arr    = wp_get_attachment_image_src( $att_id, $size_slug );
			$out['url'] = ! empty( $src_arr[0] ) ? $src_arr[0] : wp_get_attachment_url( $att_id );
			// Alt is taken from the attachment's alt meta; never fall back to the
			// filename/title (an accessibility anti-pattern). When the id is used
			// with wp_get_attachment_image(), WordPress reads this meta itself.
			$out['alt'] = get_post_meta( $att_id, '_wp_attachment_image_alt', true );
			$out['id']  = $att_id;
			return $out;
		}
	}
	if ( is_array( $value ) && ! empty( $value ) ) {
		$maybe_id = $value['ID'] ?? $value['id'] ?? null;
		if ( is_numeric( $maybe_id ) ) {
			$att_id     = (int) $maybe_id;
			$src_arr    = wp_get_attachment_image_src( $att_id, $size_slug );
			$out['url'] = ! empty( $src_arr[0] ) ? $src_arr[0] : wp_get_attachment_url( $att_id );
			$alt_meta   = get_post_meta( $att_id, '_wp_attachment_image_alt', true );
			$alt_in     = $value['alt'] ?? '';
			$out['alt'] = $alt_in !== '' ? $alt_in : $alt_meta;
			$out['id']  = $att_id;
			return $out;
		}
		if ( ! empty( $value['sizes'] ) && is_array( $value['sizes'] ) && ! empty( $value['sizes'][ $size_slug ] ) ) {
			$out['url'] = esc_url_raw( $value['sizes'][ $size_slug ] );
			$out['alt'] = isset( $value['alt'] ) ? wp_strip_all_tags( $value['alt'] ) : ( $value['title'] ?? '' );
			return $out;
		}
		if ( ! empty( $value['url'] ) ) {
			$out['url'] = esc_url_raw( $value['url'] );
			$out['alt'] = isset( $value['alt'] ) ? wp_strip_all_tags( $value['alt'] ) : ( $value['title'] ?? '' );
			return $out;
		}
	}
	if ( is_string( $value ) && filter_var( $value, FILTER_VALIDATE_URL ) ) {
		$out['url'] = esc_url_raw( $value );
	}
	return $out;
};

// ─── Image resolution (dynamic → ID → URL) ───────────────────────────────────

$img_html  = '';
$link_href = '';

$target_post_id = ( $source_type === 'specific' && $post_id_attr ) ? $post_id_attr : get_the_ID();

// Featured image
if ( $is_featured_dynamic && $target_post_id ) {
	$thumb_id = get_post_thumbnail_id( $target_post_id );
	if ( $thumb_id ) {
		$src_arr  = wp_get_attachment_image_src( $thumb_id, $size_slug );
		$src      = ! empty( $src_arr[0] ) ? $src_arr[0] : wp_get_attachment_url( $thumb_id );
		// Alt resolved by wp_get_attachment_image() from the attachment's alt meta.
		if ( $src ) {
			$img_html = $build_image_markup( $src, '', $thumb_id );
			if ( $link_option === 'post' ) { $link_href = get_permalink( $target_post_id ); }
		}
	}
}

// Library image (by ID)
if ( ! $img_html && $image_id ) {
	$src_arr  = wp_get_attachment_image_src( $image_id, $size_slug );
	$src      = ! empty( $src_arr[0] ) ? $src_arr[0] : wp_get_attachment_url( $image_id );
	// Alt resolved by wp_get_attachment_image() from the attachment's alt meta.
	if ( $src ) {
		$img_html = $build_image_markup( $src, '', $image_id, true );
		if ( $custom_link ) { $link_href = $custom_link; }
	}
}

// External URL
if ( ! $img_html && ! empty( $image_url ) ) {
	$img_html = $build_image_markup( $image_url, $alt_external, 0, true );
	if ( $custom_link ) { $link_href = $custom_link; }
}

// Author avatar
if ( ! $img_html && ( $selected_tag === 'author_avatar' || ( is_string( $dynamic_tag ) && strpos( $dynamic_tag, 'author_avatar' ) !== false ) ) ) {
	if ( $target_post_id ) {
		$post_obj  = get_post( $target_post_id );
		$author_id = $post_obj ? (int) $post_obj->post_author : 0;
		if ( $author_id > 0 ) {
			$avatar_url = get_avatar_url( $author_id, [ 'size' => 96 ] );
			if ( $avatar_url ) {
				$author_name = get_the_author_meta( 'display_name', $author_id );
				/* translators: %s: author display name. */
				$alt      = $author_name ? sprintf( __( 'Avatar of %s', 'axcelersblocks' ), $author_name ) : __( 'Author avatar', 'axcelersblocks' );
				$img_html = $build_image_markup( $avatar_url, $alt, 0 );
				if ( $link_option === 'author' ) { $link_href = get_author_posts_url( $author_id ); }
				elseif ( $link_option === 'post' ) { $link_href = $target_post_id ? get_permalink( $target_post_id ) : ''; }
			}
		}
	}
}

// ACF field
if ( ! $img_html && ( $selected_tag === 'acf_field' || ( is_string( $dynamic_tag ) && strpos( $dynamic_tag, 'acf_field' ) !== false ) ) ) {
	$val = null;
	if ( function_exists( 'get_field' ) ) {
		if ( $acf_scope === 'options' ) {
			$val = $acf_field ? get_field( $acf_field, 'option' ) : null;
		} elseif ( $source_entity === 'term' && $term_id_attr ) {
			$val = $acf_field ? get_field( $acf_field, "{$taxonomy}_{$term_id_attr}" ) : null;
		} else {
			$val = ( $acf_field && $target_post_id ) ? get_field( $acf_field, $target_post_id ) : null;
		}
	} else {
		if ( $acf_scope === 'options' )                              { $val = get_option( $acf_field ); }
		elseif ( $source_entity === 'term' && $term_id_attr )        { $val = get_term_meta( $term_id_attr, $acf_field, true ); }
		elseif ( $target_post_id )                                   { $val = get_post_meta( $target_post_id, $acf_field, true ); }
	}
	$img = $normalize_to_image( $val, $size_slug );
	if ( ! empty( $img['url'] ) ) {
		$img_html = $build_image_markup( $img['url'], $img['alt'], $img['id'] ?? 0 );
		if ( $link_option === 'term' && $term_id_attr ) {
			$term_link = get_term_link( $term_id_attr, $taxonomy );
			if ( ! is_wp_error( $term_link ) ) { $link_href = $term_link; }
		} elseif ( $link_option === 'post' ) {
			$link_href = $target_post_id ? get_permalink( $target_post_id ) : '';
		}
	}
}

// Post meta
if ( ! $img_html && ( $selected_tag === 'post_meta' || ( is_string( $dynamic_tag ) && strpos( $dynamic_tag, 'post_meta' ) !== false ) ) && $target_post_id && $meta_key ) {
	$raw = get_post_meta( $target_post_id, $meta_key, true );
	$img = $normalize_to_image( $raw, $size_slug );
	if ( ! empty( $img['url'] ) ) {
		$img_html = $build_image_markup( $img['url'], $img['alt'], $img['id'] ?? 0 );
		if ( $link_option === 'post' ) { $link_href = get_permalink( $target_post_id ); }
	}
}

// Term meta
if ( ! $img_html && ( $selected_tag === 'term_meta' || ( is_string( $dynamic_tag ) && strpos( $dynamic_tag, 'term_meta' ) !== false ) ) && $term_id_attr && $meta_key ) {
	$raw = get_term_meta( $term_id_attr, $meta_key, true );
	$img = $normalize_to_image( $raw, $size_slug );
	if ( ! empty( $img['url'] ) ) {
		$term_name = get_term_field( 'name', $term_id_attr, $taxonomy );
		$alt_text  = $img['alt'] ?: ( is_wp_error( $term_name ) ? '' : $term_name );
		$img_html  = $build_image_markup( $img['url'], $alt_text, $img['id'] ?? 0 );
		if ( $link_option === 'term' ) {
			$term_link = get_term_link( $term_id_attr, $taxonomy );
			if ( ! is_wp_error( $term_link ) ) { $link_href = $term_link; }
		}
	}
}

// No image resolved. By default the block renders nothing on the front end; when
// the "Show placeholder when empty" option is on, render the same empty-state UI
// the editor shows so the layout slot stays visible.
if ( empty( $img_html ) ) {
	if ( empty( $attributes['showEmptyPlaceholder'] ) ) {
		return;
	}
	$img_html = '<div class="axcelersblocks-image__placeholder"><div class="axcelersblocks-image__empty">'
		. '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
		. '<rect x="3" y="3" width="18" height="18" rx="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline>'
		. '</svg><span>' . esc_html__( 'No image', 'axcelersblocks' ) . '</span></div></div>';
	$contains_native_img = true; // trusted, self-built markup — skip wp_kses_post (keeps the inline SVG intact).
}

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

$figure_html = sprintf( '<figure %1$s>%2$s</figure>', $wrapper_attrs, $img_html );
// Skip wp_kses_post for trusted, WordPress-generated markup (inline SVG, <picture>,
// or wp_get_attachment_image output) — kses would strip srcset / sizes / fetchpriority.
// Only the plain external-URL <img> path (user-supplied) needs sanitizing.
$figure_output = ( $contains_inline_svg || $contains_picture_element || $contains_native_img )
	? $figure_html
	: wp_kses_post( $figure_html );

if ( ! empty( $link_href ) ) {
	$link_href  = esc_url( $link_href );
	$link_class = sanitize_html_class( $unique_class ) . '-link';
	$target_rel = $open_in_new ? ' target="_blank"' : '';
	printf(
		'<a href="%1$s" class="%2$s"%3$s%4$s%5$s%6$s>%7$s</a>',
		esc_url( $link_href ),
		esc_attr( $link_class ),
		$target_rel, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Hardcoded safe attribute fragment.
		$rel_attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped 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.
		$figure_output // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- sanitized by wp_kses_post() or built from escaped content.
	);
} else {
	echo $figure_output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- sanitized by wp_kses_post() or built from escaped content.
}
// phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
