<?php
/**
 * Seventhqueen\Typer\Image_Sizes\Component class
 *
 * @package typer
 */

namespace Seventhqueen\Typer\Image_Sizes;

use Seventhqueen\Typer\Component_Interface;
use function Seventhqueen\Typer\typer;
use WP_Post;
use function add_filter;

/**
 * Class for managing responsive image sizes.
 */
class Component implements Component_Interface {

	/**
	 * Gets the unique identifier for the theme component.
	 *
	 * @return string Component slug.
	 */
	public function get_slug() {
		return 'image_sizes';
	}

	/**
	 * Adds the action and filter hooks to integrate with WordPress.
	 */
	public function initialize() {
		add_filter( 'wp_calculate_image_sizes', [ $this, 'filter_content_image_sizes_attr' ], 10, 2 );
		add_filter( 'wp_get_attachment_image_attributes', [ $this, 'filter_post_thumbnail_sizes_attr' ], 10, 3 );

		add_action( 'after_setup_theme', [ $this, 'register_image_sizes' ] );
		add_filter( 'image_size_names_choose', [ $this, 'custom_image_sizes' ] );
		// add_filter( 'image_downsize', [ $this, 'dynamic_image_downsize' ], 10, 3 );
	}

	/**
	 * Adds custom image sizes attribute to enhance responsive image functionality for content images.
	 *
	 * @param string $sizes A source size value for use in a 'sizes' attribute.
	 * @param array $size Image size. Accepts an array of width and height
	 *                      values in pixels (in that order).
	 *
	 * @return string A source size value for use in a content image 'sizes' attribute.
	 */
	public function filter_content_image_sizes_attr( $sizes, array $size ) {
		if ( typer()->is_primary_sidebar_active() ) {
			$sizes = '(min-width: 960px) 75vw, 100vw';
		}

		return $sizes;
	}

	/**
	 * Adds custom image sizes attribute to enhance responsive image functionality for post thumbnails.
	 *
	 * @param array $attr Attributes for the image markup.
	 * @param WP_Post $attachment Attachment post object.
	 * @param string|array $size Registered image size or flat array of height and width dimensions.
	 *
	 * @return array The filtered attributes for the image markup.
	 */
	public function filter_post_thumbnail_sizes_attr( array $attr, WP_Post $attachment, $size ) {
		$listing     = typer()->get_post_data( 'listing_type' );
		$media_width = typer()->get_post_data( 'media_width' );
		$media_size  = typer()->get_post_data( 'media_size' );

		$layout_width    = typer()->get_option( 'container_width_general' );
		$small_item_cols = typer()->get_option( 'blog_masonry_small_items' );
		$wide_item_cols  = typer()->get_option( 'blog_masonry_wide_items' );

		if ( typer()->is_primary_sidebar_active() || typer()->is_secondary_sidebar_active() ) {
			$layout_width = 'small';
		}

		$sizes = '';

		switch ( $listing ) {
			case 'list':
				if ( $media_size === 'auto' || $media_width === 'wide' ) {
					$sizes = $this->add_img_query( 350, 400, $sizes );
					$sizes = $this->add_img_query( 700, 768, $sizes );

					if ( $layout_width === 'small' ) {
						$sizes = $this->add_img_query( 240, null, $sizes );
					} else {
						$sizes = $this->add_img_query( 240, 992, $sizes );
						$sizes = $this->add_img_query( 350, null, $sizes );
					}
				} else if ( $media_width === 'normal' ) {
					$sizes = $this->add_img_query( 100, 400, $sizes );
					$sizes = $this->add_img_query( 150, 768, $sizes );

					if ( $layout_width === 'small' ) {
						$sizes = $this->add_img_query( 240, null, $sizes );
					} else {
						$sizes = $this->add_img_query( 240, 992, $sizes );
						$sizes = $this->add_img_query( 350, null, $sizes );
					}
				}
				break;
			case 'list-big':
				if ( $media_size === 'auto' ) {
					$sizes = $this->add_img_query( 240, 400, $sizes );
					$sizes = $this->add_img_query( 350, 992, $sizes );
				} else {
					$sizes = $this->add_img_query( 350, 400, $sizes );
				}

				if ( ( $layout_width === 'small' ) && $media_size === 'normal' ) {
					$sizes = $this->add_img_query( 700, null, $sizes );
				} else {
					$sizes = $this->add_img_query( 1100, null, $sizes );
				}
				break;
			case 'list-widget':
				$sizes = $this->add_img_query( 100, 400, $sizes );
				$sizes = $this->add_img_query( 150, 768, $sizes );
				$sizes = $this->add_img_query( 240, 992, $sizes );
				$sizes = $this->add_img_query( 100, 1200, $sizes );
				$sizes = $this->add_img_query( 120, null, $sizes );
				break;
			case 'list-featured':
				if ( $media_size === 'auto' ) {
					$sizes = $this->add_img_query( 240, 450, $sizes );
					$sizes = $this->add_img_query( 350, 576, $sizes );
					$sizes = $this->add_img_query( 240, null, $sizes );
				} else {
					$sizes = $this->add_img_query( 350, null, $sizes );
				}
				break;
			case 'grid':
				if ( $layout_width === 'small' ) {
					$sizes = $this->add_img_query( 350, 768, $sizes );
					$sizes = $this->add_img_query( 700, null, $sizes );
				} else {
					$wide_cols = typer()->get_option( 'blog_grid_wide_items' );
					$sizes     = $this->add_img_query( 350, 450, $sizes );

					if ( $wide_cols['tablet'] === '3' ) {
						$sizes = $this->add_img_query( 350, 992, $sizes );
					} elseif ( $wide_cols['tablet'] === '12' ) {
						$sizes = $this->add_img_query( 700, 768, $sizes );
					}

					if ( $wide_cols['desktop'] === '3' ) {
						$sizes = $this->add_img_query( 700, null, $sizes );
					} elseif ( $wide_cols['desktop'] === '12' ) {
						$sizes = $this->add_img_query( 1100, null, $sizes );
					}
				}
				break;
			case 'masonry':
				if ( $layout_width === 'small' ) {
					if ( $media_width === 'normal' ) {
						$sizes = $this->add_img_query( 100, 450, $sizes );
						$sizes = $this->add_img_query( 150, 768, $sizes );

						if ( $small_item_cols['tablet'] === '6' ) {
							$sizes = $this->add_img_query( 100, 992, $sizes );
						} elseif ( $small_item_cols['tablet'] === '12' ) {
							$sizes = $this->add_img_query( 240, 992, $sizes );
						}

						if ( $small_item_cols['desktop'] === '6' ) {
							$sizes = $this->add_img_query( 100, null, $sizes );
						} elseif ( $small_item_cols['desktop'] === '12' ) {
							$sizes = $this->add_img_query( 240, null, $sizes );
						}
					} elseif ( $media_width === 'wide' ) {
						$sizes = $this->add_img_query( 240, 360, $sizes );
						$sizes = $this->add_img_query( 350, 480, $sizes );
						$sizes = $this->add_img_query( 700, 768, $sizes );

						if ( $small_item_cols['tablet'] === '6' ) {
							$sizes = $this->add_img_query( 350, 992, $sizes );
						} elseif ( $small_item_cols['tablet'] === '12' ) {
							$sizes = $this->add_img_query( 700, 992, $sizes );
						}

						if ( $small_item_cols['desktop'] === '6' ) {
							$sizes = $this->add_img_query( 350, null, $sizes );
						} elseif ( $small_item_cols['desktop'] === '12' ) {
							$sizes = $this->add_img_query( 700, null, $sizes );
						}
					}
				} else if ( $media_width === 'normal' ) {
					$sizes = $this->add_img_query( 100, 450, $sizes );
					$sizes = $this->add_img_query( 150, 768, $sizes );

					if ( $wide_item_cols['tablet'] === '6' ) {
						$sizes = $this->add_img_query( 100, 992, $sizes );
					} elseif ( $wide_item_cols['tablet'] === '12' ) {
						$sizes = $this->add_img_query( 240, 992, $sizes );
					}

					if ( $wide_item_cols['desktop'] === '6' ) {
						$sizes = $this->add_img_query( 150, null, $sizes );
					} elseif ( $wide_item_cols['desktop'] === '12' ) {
						$sizes = $this->add_img_query( 240, 1200, $sizes );
						$sizes = $this->add_img_query( 350, null, $sizes );
					} else {
						$sizes = $this->add_img_query( 100, null, $sizes );
					}
				} elseif ( $media_width === 'wide' ) {
					$sizes = $this->add_img_query( 100, 450, $sizes );
					$sizes = $this->add_img_query( 150, 768, $sizes );

					if ( $wide_item_cols['tablet'] === '12' ) {
						$sizes = $this->add_img_query( 240, 992, $sizes );
					} else {
						$sizes = $this->add_img_query( 100, 992, $sizes );
					}

					if ( $wide_item_cols['desktop'] === '4' ) {
						$sizes = $this->add_img_query( 350, null, $sizes );
					} elseif ( $wide_item_cols['desktop'] === '3' ) {
						$sizes = $this->add_img_query( 240, null, $sizes );
					} else {
						$sizes = $this->add_img_query( 700, null, $sizes );
					}
				}
				break;
			default:
		}

		$attr['sizes'] = $sizes ?: '100vw';

		return $attr;
	}

	/**
	 * Image media queries helper
	 *
	 * @param $size
	 * @param null $resolution
	 * @param string $query
	 * @param bool $max
	 *
	 * @return string
	 */
	private function add_img_query( $size, $resolution = null, $query = '', $max = true ) {
		if ( $query ) {
			$query .= ', ';
		}

		if ( $resolution ) {
			$query .= '(' . ( $max ? 'max' : 'min' ) . '-width: ' . $resolution . 'px) ' . $size . 'px';
		} else {
			$query .= $size . 'px';
		}

		return $query;
	}

	/**
	 * Registers image sizes
	 */
	public function register_image_sizes() {
		add_image_size(
			'typer-img-wide-xxl',
			1100,
			620,
			true
		);

		add_image_size(
			'typer-img-wide-xl',
			700,
			400,
			true
		);

		add_image_size(
			'typer-img-xxl',
			700,
			700,
			true
		);

		add_image_size(
			'typer-img-xl',
			350,
			560,
			true
		);

		add_image_size(
			'typer-img-lg',
			350,
			350,
			true
		);

		add_image_size(
			'typer-img-md',
			240,
			240,
			true
		);

		add_image_size(
			'typer-img-sm',
			120,
			120,
			true
		);

		add_image_size(
			'typer-img-xs',
			100,
			100,
			true
		);

		add_image_size(
			'typer-lazy',
			45,
			9999
		);
	}

	/**
	 * Add registered image sizes to size choices
	 *
	 * @param $sizes
	 *
	 * @return array
	 */
	public function custom_image_sizes( $sizes ) {
		return array_merge( $sizes, [
			'typer-img-wide-xxl' => esc_html__( 'Typer wide mega large image', 'typer' ),
			'typer-img-wide-xl'  => esc_html__( 'Typer wide large image', 'typer' ),
			'typer-img-xxl'      => esc_html__( 'Typer mega large image', 'typer' ),
			'typer-img-xl'       => esc_html__( 'Typer extra large image', 'typer' ),
			'typer-img-lg'       => esc_html__( 'Typer large image', 'typer' ),
			'typer-img-md'       => esc_html__( 'Typer medium image', 'typer' ),
			'typer-img-sm'       => esc_html__( 'Typer small image', 'typer' ),
			'typer-img-xs'       => esc_html__( 'Typer extra small image', 'typer' ),
			'typer-lazy'         => esc_html__( 'Typer for lazy load', 'typer' ),
		] );
	}

	/**
	 * Filter the output of image_downsize() to return dynamically generated images for intermediate or inline sizes.
	 * Example usage with on-the-fly dimensions:
	 * In template file: the_post_thumbnail( [ 565, 337 ] );
	 * Will create a new named size called '565x337'
	 *
	 * @param bool $downsize Whether to short-circuit the image downsize. Default passed in true. (ignored in filter)
	 * @param int $id Attachment ID for image.
	 * @param array|string|int $size Size of image, either array or string. Default passed in 'medium'.
	 *
	 * @return array|bool            [ Image URL, width, height, bool ($is_intermediate) ] OR false if not resizing
	 */
	public function dynamic_image_downsize( $downsize = true, $id, $size ) {
		$meta  = wp_get_attachment_metadata( $id );
		$sizes = $this->get_image_sizes();

		// use specific w/h dimensions requested as array
		if ( is_array( $size ) ) {
			if ( sizeof( $size ) === 2 ) {
				list( $width, $height ) = $size;

				// make a size name from requested dimensions as a fallback for saving to meta
				$size = $width . 'x' . $height;
				$crop = true;
			} else {
				return false;
			}
		}

		if ( array_key_exists( $size, $sizes ) ) {
			extract( $sizes[ $size ] );
		} elseif ( preg_match( '#^(\d+)x(\d+)$#', $size, $matches ) ) {
			// ex 200x200
			$width  = (int) $matches[1];
			$height = (int) $matches[2];
			$crop   = true;
		} else {
			return false;
		}

		// if dimensions match a named size, use that instead
		foreach ( $sizes as $size_name => $size_atts ) {
			if ( $width === $size_atts['width'] && $height === $size_atts['height'] ) {
				$size = $size_name;
			}
		}

		// exit if there's already a generated image with the right dimensions
		// the default downsize function would use it anyway (even if it had a different name)
		if ( array_key_exists( $size, $meta['sizes'] ) && $width === $meta['sizes'][ $size ]['width'] && $height === $meta['sizes'][ $size ]['height'] ) {
			return false;
		}

		// nothing matching size exists, generate and save new image from original
		$intermediate = image_make_intermediate_size( get_attached_file( $id ), $width, $height, $crop );

		// exit if failed creating image
		if ( ! is_array( $intermediate ) ) {
			return false;
		}

		// save the new size parameters in meta (to find it next time)
		$meta['sizes'][ $size ] = $intermediate;
		wp_update_attachment_metadata( $id, $meta );

		// this step is from the default image_downsize function in media.php
		// "might need to further constrain it if content_width is narrower"
		list( $width, $height ) = image_constrain_size_for_editor( $intermediate['width'], $intermediate['height'], $size );

		// use path of original file with new filename
		$original_url      = wp_get_attachment_url( $id );
		$original_basename = wp_basename( $original_url );
		$img_url           = str_replace( $original_basename, $intermediate['file'], $original_url );

		return [ $img_url, $width, $height, true ];
	}

	// Useful helper function from codex example: http://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes
	public function get_image_sizes( $size = '' ) {
		global $_wp_additional_image_sizes;
		$sizes                        = [];
		$get_intermediate_image_sizes = get_intermediate_image_sizes();

		// Create the full array with sizes and crop info
		foreach ( $get_intermediate_image_sizes as $_size ) {
			if ( in_array( $_size, [ 'thumbnail', 'medium', 'large' ] ) ) {
				$sizes[ $_size ]['width']  = get_option( $_size . '_size_w' );
				$sizes[ $_size ]['height'] = get_option( $_size . '_size_h' );
				$sizes[ $_size ]['crop']   = (bool) get_option( $_size . '_crop' );
			} elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
				$sizes[ $_size ] = [
					'width'  => $_wp_additional_image_sizes[ $_size ]['width'],
					'height' => $_wp_additional_image_sizes[ $_size ]['height'],
					'crop'   => $_wp_additional_image_sizes[ $_size ]['crop']
				];
			}
		}

		// Get only 1 size if found
		if ( $size ) {
			return isset( $sizes[ $size ] ) ? $sizes[ $size ] : false;
		}

		return $sizes;
	}

}
