<?php

namespace Fotogenic_AI\Compat\Media;

use Fotogenic_AI\Image_Source_Resolver;
use Fotogenic_AI\MediaQueryAdapter;
use Fotogenic_AI\Workflow_Item_Identity;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WordPress Media Library query adapter — attachments (images), search by title, paginated.
 * Only exposes items when current_user_can( 'upload_files' ); otherwise returns empty list.
 */
final class Media_Query_Adapter_Wp implements MediaQueryAdapter {

	private const POST_MIME_TYPE_IMAGE = 'image';
	private const FILTER_CACHE_GROUP = 'fotogenic_ai_media_filters';
	private const FILTER_BATCH_SIZE = 200;

	/**
	 * List/search media. Returns empty list if user cannot upload_files.
	 *
	 * @param string $q        Search query (title).
	 * @param int    $page     Page number (1-based).
	 * @param int    $per_page Items per page.
	 * @param array  $filters  Authoritative Media Library filters.
	 * @return array{items: array, totalItems: int, totalPages: int}
	 */
	public function list_media( string $q, int $page, int $per_page, array $filters = [] ): array {
		if ( ! current_user_can( 'upload_files' ) ) {
			return [
				'items'      => [],
				'totalItems' => 0,
				'totalPages' => 1,
			];
		}

		$per_page = max( 1, min( 100, (int) $per_page ) );
		$page     = max( 1, (int) $page );

		$filters = $this->normalize_filters( $filters );
		$args    = [
			'post_type'      => 'attachment',
			'post_status'    => 'inherit',
			'post_mime_type' => self::POST_MIME_TYPE_IMAGE,
			'posts_per_page' => $per_page,
			'paged'          => $page,
			'orderby'        => 'date',
			'order'          => 'DESC',
		];

		$search = trim( (string) $q );
		if ( '' !== $search ) {
			$args['s'] = $search;
		}
		$this->apply_database_filters( $args, $filters );

		if ( 'all' !== $filters['orientation'] || 'all' !== $filters['size'] ) {
			return $this->list_media_with_file_filters( $args, $page, $per_page, $filters );
		}

		$query = new \WP_Query( $args );
		$posts = $query->posts ?? [];
		$items = [];

		foreach ( $posts as $post ) {
			if ( ! $post instanceof \WP_Post ) {
				continue;
			}
			$item = $this->build_item( $post->ID );
			if ( is_array( $item ) && ! empty( $item ) ) {
				$items[] = $item;
			}
		}

		$total_items = (int) ( $query->found_posts ?? 0 );
		$total_pages = $per_page > 0 ? (int) ceil( $total_items / $per_page ) : 1;
		$total_pages = max( 1, $total_pages );

		return [
			'items'      => $items,
			'totalItems' => $total_items,
			'totalPages' => $total_pages,
		];
	}

	/** @return array{type:string,date:string,orientation:string,size:string} */
	private function normalize_filters( array $filters ): array {
		$allowed = [
			'type'        => [ 'all', 'jpg', 'png', 'webp' ],
			'date'        => [ 'all', 'today', 'week', 'month', 'older' ],
			'orientation' => [ 'all', 'square', 'landscape', 'portrait' ],
			'size'        => [ 'all', 'under_300kb', '300kb_and_over' ],
		];
		$normalized = [];
		foreach ( $allowed as $key => $values ) {
			$value = sanitize_key( (string) ( $filters[ $key ] ?? 'all' ) );
			$normalized[ $key ] = in_array( $value, $values, true ) ? $value : 'all';
		}
		return $normalized;
	}

	private function apply_database_filters( array &$args, array $filters ): void {
		$mime_types = [
			'jpg'  => [ 'image/jpeg' ],
			'png'  => [ 'image/png' ],
			'webp' => [ 'image/webp' ],
		];
		if ( isset( $mime_types[ $filters['type'] ] ) ) {
			$args['post_mime_type'] = $mime_types[ $filters['type'] ];
		}

		$date_queries = [
			'today' => [ 'after' => 'today', 'inclusive' => true ],
			'week'  => [ 'after' => '1 week ago', 'inclusive' => true ],
			'month' => [ 'after' => '1 month ago', 'inclusive' => true ],
			'older' => [ 'before' => '1 month ago', 'inclusive' => false ],
		];
		if ( isset( $date_queries[ $filters['date'] ] ) ) {
			$args['date_query'] = [ $date_queries[ $filters['date'] ] ];
		}
	}

	/** @return array{items:array,totalItems:int,totalPages:int} */
	private function list_media_with_file_filters( array $base_args, int $page, int $per_page, array $filters ): array {
		$cache_key = 'ids_' . md5(
			wp_json_encode(
				[
					'blog'    => get_current_blog_id(),
					'user'    => get_current_user_id(),
					'query'   => $base_args,
					'filters' => $filters,
					'posts'   => function_exists( 'wp_cache_get_last_changed' ) ? wp_cache_get_last_changed( 'posts' ) : '',
				]
			)
		);
		$ids = wp_cache_get( $cache_key, self::FILTER_CACHE_GROUP );
		if ( ! is_array( $ids ) ) {
			$ids        = [];
			$query_page = 1;
			do {
				$query = new \WP_Query(
					array_merge(
						$base_args,
						[
							'fields'         => 'ids',
							'posts_per_page' => self::FILTER_BATCH_SIZE,
							'paged'          => $query_page,
						]
					)
				);
				foreach ( (array) $query->posts as $attachment_id ) {
					$attachment_id = absint( $attachment_id );
					if ( $attachment_id > 0 && $this->matches_file_filters( $attachment_id, $filters ) ) {
						$ids[] = $attachment_id;
					}
				}
				++$query_page;
			} while ( $query_page <= max( 1, (int) $query->max_num_pages ) );
			wp_cache_set( $cache_key, $ids, self::FILTER_CACHE_GROUP, MINUTE_IN_SECONDS );
		}

		$total_items = count( $ids );
		$total_pages = max( 1, (int) ceil( $total_items / $per_page ) );
		$offset      = ( $page - 1 ) * $per_page;
		$items       = [];
		foreach ( array_slice( $ids, $offset, $per_page ) as $attachment_id ) {
			$item = $this->build_item( (int) $attachment_id );
			if ( is_array( $item ) && ! empty( $item ) ) {
				$items[] = $item;
			}
		}

		return [
			'items'      => $items,
			'totalItems' => $total_items,
			'totalPages' => $total_pages,
		];
	}

	private function matches_file_filters( int $attachment_id, array $filters ): bool {
		$meta        = wp_get_attachment_metadata( $attachment_id );
		$width       = max( 0, (int) ( $meta['width'] ?? 0 ) );
		$height      = max( 0, (int) ( $meta['height'] ?? 0 ) );
		$orientation = $this->orientation( $width, $height );
		if ( 'all' !== $filters['orientation'] && $filters['orientation'] !== $orientation ) {
			return false;
		}

		if ( 'all' === $filters['size'] ) {
			return true;
		}
		$path = function_exists( 'wp_get_original_image_path' ) ? wp_get_original_image_path( $attachment_id ) : '';
		if ( ! is_string( $path ) || '' === $path ) {
			$path = get_attached_file( $attachment_id );
		}
		$bytes = is_string( $path ) && is_readable( $path ) ? (int) wp_filesize( $path ) : 0;
		if ( $bytes <= 0 ) {
			return false;
		}
		return 'under_300kb' === $filters['size'] ? $bytes < 307200 : $bytes >= 307200;
	}

	private function orientation( int $width, int $height ): string {
		if ( $width <= 0 || $height <= 0 ) {
			return '';
		}
		if ( $width === $height ) {
			return 'square';
		}
		return $width > $height ? 'landscape' : 'portrait';
	}

	/**
	 * Get media summary. Returns null if not found; WP_Error when no permission.
	 *
	 * @param int $id Attachment ID.
	 * @return array|null|\WP_Error
	 */
	public function get_media_summary( int $id ) {
		if ( ! current_user_can( 'upload_files' ) ) {
			return new \WP_Error( 'forbidden', __( 'You do not have permission to access media.', 'fotogenic-ai' ), [ 'status' => 403 ] );
		}

		$post = get_post( $id );
		if ( ! $post || 'attachment' !== $post->post_type ) {
			return null;
		}

		$mime = get_post_mime_type( $id );
		if ( ! $mime || strpos( $mime, 'image/' ) !== 0 ) {
			return null;
		}

		return $this->build_item( $id );
	}

	/**
	 * Build a browser-safe list item with authoritative workflow eligibility.
	 *
	 * @param int $id Attachment ID.
	 * @return array{id:int,label:string,imageUrl:string,sourceAttachmentId:int,target:array,width:int,height:int,mime:string,bytes:int,dateAdded:string,dateLabel:string,orientation:string,eligible:bool,eligibilityReason:string}|\WP_Error
	 */
	private function build_item( int $id ) {
		$post = get_post( $id );
		$path = get_attached_file( $id );
		$name = $post && $post->post_title ? (string) $post->post_title : ( is_string( $path ) ? basename( $path ) : '' );
		$name = \Fotogenic_AI\fotogenic_ai_plain_text_label( $name );
		$mime = get_post_mime_type( $id ) ?: '';
		$meta = wp_get_attachment_metadata( $id );
		$width  = isset( $meta['width'] ) ? (int) $meta['width'] : 0;
		$height = isset( $meta['height'] ) ? (int) $meta['height'] : 0;

		// The shared Media grid needs a larger derivative, including on high-density screens.
		$preview = \Fotogenic_AI\Media_Saver::get_attachment_view_url( $id, 'medium_large' );
		$url     = \Fotogenic_AI\Media_Saver::get_attachment_view_url( $id, 'full' );
		$eligibility = current_user_can( 'edit_post', $id )
			? Image_Source_Resolver::instance()->get_workflow_attachment_eligibility( $id )
			: [
				'eligible'          => false,
				'eligibilityReason' => __( 'You do not have permission to use this image.', 'fotogenic-ai' ),
				'bytes'             => 0,
				'mime'              => '',
			];
		$eligible           = true === $eligibility['eligible'];
		$bytes              = (int) $eligibility['bytes'];
		$eligibility_reason = (string) $eligibility['eligibilityReason'];
		if ( $eligible ) {
			$mime = (string) $eligibility['mime'];
		}
		if ( $eligible && ( ! $preview || ! $url ) ) {
			$eligible           = false;
			$eligibility_reason = __( 'A preview is unavailable for this image. Replace or remove it to continue.', 'fotogenic-ai' );
		}
		$target = Workflow_Item_Identity::resolve_target( 'media', $id );
		if ( is_wp_error( $target ) ) {
			return $target;
		}

		return [
			'id'       => (int) $id,
			'label'    => (string) $name,
			'imageUrl' => $preview ? (string) $preview : '',
			'sourceAttachmentId' => (int) $id,
			'target'   => $target,
			'width'    => $width,
			'height'   => $height,
			'mime'     => (string) $mime,
			'bytes'    => $bytes,
			'dateAdded' => $post instanceof \WP_Post ? mysql_to_rfc3339( $post->post_date_gmt ) : '',
			'dateLabel' => $post instanceof \WP_Post ? wp_date( get_option( 'date_format' ), strtotime( $post->post_date_gmt . ' UTC' ) ) : '',
			'orientation' => $this->orientation( $width, $height ),
			'eligible' => $eligible,
			'eligibilityReason' => $eligibility_reason,
		];
	}
}
