<?php
/**
 * UGC Library REST API Controller.
 *
 * Provides:
 *  - GET  /ugcify/v1/library        – paginated list of media items from UGC reviews
 *  - POST /ugcify/v1/library/upload – admin file upload (creates a new approved review with media)
 *
 * @package Ugcify\Admin\API
 */

namespace Ugcify\Admin\API;

use Ugcify\Review\ReviewMeta;
use Ugcify\Review\Review;
use Ugcify\Database\ReviewRepository;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_Error;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class UgcLibraryAPI

 * phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
 */
class UgcLibraryAPI extends WP_REST_Controller {

	/**
	 * Namespace.
	 *
	 * @var string
	 */
	protected $namespace = 'ugcify/v1';

	/**
	 * Rest base.
	 *
	 * @var string
	 */
	protected $rest_base = 'library';

	/**
	 * Review meta helper.
	 *
	 * @var ReviewMeta
	 */
	private $meta;

	/**
	 * Review repository.
	 *
	 * @var ReviewRepository
	 */
	private $repository;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->meta       = new ReviewMeta();
		$this->repository = new ReviewRepository();
	}

	/**
	 * Register routes.
	 *
	 * @return void
	 */
	public function register_routes() {
		// List media items.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_items' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'page'       => array(
							'type'    => 'integer',
							'default' => 1,
							'minimum' => 1,
						),
						'per_page'   => array(
							'type'    => 'integer',
							'default' => 24,
							'minimum' => 1,
							'maximum' => 100,
						),
						'product_id' => array(
							'type'    => 'integer',
							'default' => 0,
						),
						'media_type' => array(
							'type'    => 'string',
							'default' => 'all',
							'enum'    => array( 'all', 'image', 'video' ),
						),
						'search'     => array(
							'type'              => 'string',
							'default'           => '',
							'sanitize_callback' => 'sanitize_text_field',
						),
						'source'     => array(
							'type'    => 'string',
							'default' => 'all',
						),
					),
				),
			)
		);

		// Upload new media.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/upload',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'upload_media' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'product_id' => array(
							'type'    => 'integer',
							'default' => 0,
						),
						'status'     => array(
							'type'    => 'string',
							'default' => 'approved',
							'enum'    => array( 'approved', 'pending' ),
						),
					),
				),
			)
		);

		// Get WooCommerce products for the filter dropdown.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/products',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_products' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
				),
			)
		);
	}

	// ─────────────────────────────────────────────────────────────────
	// Permissions
	// ─────────────────────────────────────────────────────────────────

	/**
	 * Require manage_options capability.
	 *
	 * @return bool|\WP_Error
	 */
	public function check_admin_permission() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'Sorry, you are not allowed to access this resource.', 'ugcify' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	// ─────────────────────────────────────────────────────────────────
	// GET /library
	// ─────────────────────────────────────────────────────────────────

	/**
	 * List all media items from UGC reviews.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return \WP_REST_Response
	 */
	public function get_items( $request ) {
		global $wpdb;

		$page       = max( 1, (int) $request->get_param( 'page' ) );
		$per_page   = (int) $request->get_param( 'per_page' );
		$product_id = absint( $request->get_param( 'product_id' ) );
		$media_type = sanitize_key( $request->get_param( 'media_type' ) );
		$search     = sanitize_text_field( $request->get_param( 'search' ) );
		$source     = sanitize_text_field( $request->get_param( 'source' ) );

		$reviews_table = $wpdb->prefix . 'ugcify_reviews';
		$meta_table    = $wpdb->prefix . 'ugcify_review_meta';

		// Build the base query selecting reviews that have media.
		$join_clauses  = array();
		$where_clauses = array( '1=1' );
		$values        = array();

		// Always join to find reviews with at least one media item.
		$join_clauses[] = "LEFT JOIN {$meta_table} AS rm_img ON r.id = rm_img.review_id AND rm_img.meta_key = 'images'";
		$join_clauses[] = "LEFT JOIN {$meta_table} AS rm_vid ON r.id = rm_vid.review_id AND rm_vid.meta_key = 'videos'";
		$join_clauses[] = "LEFT JOIN {$meta_table} AS rm_contributor ON r.id = rm_contributor.review_id AND rm_contributor.meta_key = '_ugcify_contributor_type'";

		// Media type filter.
		if ( 'image' === $media_type ) {
			$where_clauses[] = 'rm_img.meta_id IS NOT NULL';
		} elseif ( 'video' === $media_type ) {
			$join_clauses[]  = "LEFT JOIN {$meta_table} AS rm_social ON r.id = rm_social.review_id AND rm_social.meta_key = '_social_media_url'";
			$where_clauses[] = '(rm_vid.meta_id IS NOT NULL)';
		} else {
			// all — must have at least one media
			$join_clauses[]  = "LEFT JOIN {$meta_table} AS rm_social ON r.id = rm_social.review_id AND rm_social.meta_key = '_social_media_url'";
			$where_clauses[] = '(rm_img.meta_id IS NOT NULL OR rm_vid.meta_id IS NOT NULL OR rm_social.meta_id IS NOT NULL)';
		}

		// Product filter.
		if ( $product_id > 0 ) {
			$where_clauses[] = 'r.product_id = %d';
			$values[]        = $product_id;
		}

		// Source filter.
		if ( 'all' !== $source && '' !== $source ) {
			if ( in_array( $source, array( 'ugcify', 'direct' ), true ) ) {
				$where_clauses[] = "(r.type NOT IN ('instagram','tiktok','youtube') OR r.type IS NULL)";
				$where_clauses[] = "(rm_contributor.meta_id IS NULL OR rm_contributor.meta_value <> 'influencer')";
			} elseif ( 'influencer' === $source ) {
				$where_clauses[] = "rm_contributor.meta_value = 'influencer'";
			} else {
				$where_clauses[] = 'r.type = %s';
				$values[]        = $source;
			}
		}

		// Search filter.
		if ( '' !== $search ) {
			$join_clauses[]  = "LEFT JOIN {$wpdb->posts} AS p ON r.product_id = p.ID";
			$like            = '%' . $wpdb->esc_like( $search ) . '%';
			$where_clauses[] = '(r.content LIKE %s OR r.guest_name LIKE %s OR p.post_title LIKE %s)';
			$values[]        = $like;
			$values[]        = $like;
			$values[]        = $like;
		}

		$joins_sql  = implode( ' ', $join_clauses );
		$wheres_sql = implode( ' AND ', $where_clauses );
		$offset     = ( $page - 1 ) * $per_page;

		// Count query.
		$count_sql = "SELECT COUNT(DISTINCT r.id) FROM {$reviews_table} AS r {$joins_sql} WHERE {$wheres_sql}";
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$total = (int) ( empty( $values ) ? $wpdb->get_var( $count_sql ) : $wpdb->get_var( $wpdb->prepare( $count_sql, $values ) ) );

		// Data query.
		$data_sql = "SELECT DISTINCT r.id, r.product_id, r.user_id, r.guest_name, r.type, r.status, r.created_at, r.rating, r.content
					FROM {$reviews_table} AS r {$joins_sql}
					WHERE {$wheres_sql}
					ORDER BY r.created_at DESC
					LIMIT %d OFFSET %d";

		$query_values   = array_merge( $values, array( $per_page, $offset ) );
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$rows           = $wpdb->get_results( $wpdb->prepare( $data_sql, $query_values ) );

		$items = array();
		foreach ( $rows as $row ) {
			$items[] = $this->format_item( $row );
		}

		return rest_ensure_response(
			array(
				'success'  => true,
				'items'    => $items,
				'total'    => $total,
				'page'     => $page,
				'per_page' => $per_page,
			)
		);
	}

	/**
	 * Format a single review row into a library item.
	 *
	 * @param object $row DB row.
	 * @return array
	 */
	private function format_item( $row ) {
		$review_id  = (int) $row->id;
		$product_id = (int) ( $row->product_id ?? 0 );
		$type       = (string) ( $row->type ?? 'ugcify' );

		// Pull media URLs from meta.
		$raw_meta = $this->meta->get_meta( $review_id );
		$images   = $this->extract_media_urls( $raw_meta, 'images' );
		$videos   = $this->extract_media_urls( $raw_meta, 'videos' );

		// Social media fallback URL.
		$social_url = '';
		if ( empty( $images ) && empty( $videos ) ) {
			$sv = isset( $raw_meta['_social_media_url'] ) ? $raw_meta['_social_media_url'] : '';
			if ( is_array( $sv ) ) {
				$sv = isset( $sv[0] ) ? $sv[0] : '';
			}
			$social_url = esc_url_raw( (string) $sv );
			if ( $social_url ) {
				$images[] = $social_url;
			}
		}

		// Primary media.
		$primary_url  = ! empty( $videos ) ? $videos[0] : ( ! empty( $images ) ? $images[0] : '' );
		$primary_type = ! empty( $videos ) ? 'video' : 'image';

		$raw_contributor = $raw_meta['_ugcify_contributor_type'] ?? '';
		if ( is_array( $raw_contributor ) ) {
			$raw_contributor = $raw_contributor[0] ?? '';
		}
		$contributor_type = sanitize_key( (string) maybe_unserialize( $raw_contributor ) );

		// Source label.
		$source = 'ugcify';
		$social_types = array( 'instagram', 'tiktok', 'youtube' );
		if ( 'influencer' === $contributor_type ) {
			$source = 'influencer';
		} elseif ( in_array( strtolower( $type ), $social_types, true ) ) {
			$source = strtolower( $type );
		}

		// Author name.
		$author_name = '';
		if ( ! empty( $row->user_id ) ) {
			$user        = get_user_by( 'id', $row->user_id );
			$author_name = $user ? $user->display_name : '';
		} elseif ( ! empty( $row->guest_name ) ) {
			$author_name = $row->guest_name;
		}

		// Product data.
		$product_name      = '';
		$product_thumbnail = '';
		if ( $product_id > 0 && function_exists( 'wc_get_product' ) ) {
			$product = wc_get_product( $product_id );
			if ( $product ) {
				$product_name      = $product->get_name();
				$thumb_id          = $product->get_image_id();
				$product_thumbnail = $thumb_id ? wp_get_attachment_image_url( $thumb_id, 'thumbnail' ) : '';
			}
		}

		return array(
			'id'                => $review_id,
			'review_id'         => $review_id,
			'primary_url'       => $primary_url,
			'primary_type'      => $primary_type,
			'images'            => $images,
			'videos'            => $videos,
			'source'            => $source,
			'contributor_type'  => $contributor_type,
			'is_creator_content'=> 'influencer' === $contributor_type,
			'product_id'        => $product_id,
			'product_name'      => $product_name,
			'product_thumbnail' => $product_thumbnail,
			'rating'            => (int) ( $row->rating ?? 0 ),
			'content'           => (string) ( $row->content ?? '' ),
			'author_name'       => $author_name,
			'status'            => (string) ( $row->status ?? 'pending' ),
			'created_at'        => (string) ( $row->created_at ?? '' ),
		);
	}

	/**
	 * Extract media URLs from meta key.
	 *
	 * @param array  $meta Raw meta array.
	 * @param string $key  Meta key.
	 * @return string[]
	 */
	private function extract_media_urls( array $meta, string $key ): array {
		if ( ! isset( $meta[ $key ] ) ) {
			return array();
		}

		$raw = $meta[ $key ];
		if ( is_array( $raw ) && isset( $raw[0] ) ) {
			$raw = maybe_unserialize( $raw[0] );
		}

		if ( is_string( $raw ) ) {
			$raw = '' !== trim( $raw ) ? array( $raw ) : array();
		}

		if ( ! is_array( $raw ) ) {
			return array();
		}

		$urls = array();
		foreach ( $raw as $entry ) {
			$url = esc_url_raw( (string) $entry );
			if ( $url ) {
				$urls[] = $url;
			}
		}

		return array_values( array_unique( $urls ) );
	}

	// ─────────────────────────────────────────────────────────────────
	// POST /library/upload
	// ─────────────────────────────────────────────────────────────────

	/**
	 * Upload a media file and create a new approved review entry.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function upload_media( WP_REST_Request $request ) {
		if ( ! function_exists( 'wp_handle_upload' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
			require_once ABSPATH . 'wp-admin/includes/image.php';
		}
		if ( ! function_exists( 'media_handle_upload' ) ) {
			require_once ABSPATH . 'wp-admin/includes/media.php';
		}

		$files = $request->get_file_params();

		if ( empty( $files['file'] ) || empty( $files['file']['tmp_name'] ) ) {
			return new WP_Error(
				'no_file',
				__( 'No file was uploaded.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		$file     = $files['file'];
		$allowed  = array( 'image/jpeg', 'image/png', 'image/webp', 'image/gif', 'video/mp4', 'video/webm', 'video/ogg' );
		$mime     = $file['type'];

		if ( ! in_array( $mime, $allowed, true ) ) {
			return new WP_Error(
				'invalid_file_type',
				__( 'File type not allowed. Accepted: JPEG, PNG, WebP, GIF, MP4, WebM, OGG.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		// Upload via WP media handler.
		$overrides   = array( 'test_form' => false );
		$upload_data = wp_handle_upload( $file, $overrides );

		if ( isset( $upload_data['error'] ) ) {
			return new WP_Error(
				'upload_failed',
				$upload_data['error'],
				array( 'status' => 500 )
			);
		}

		$file_url = esc_url_raw( $upload_data['url'] );
		$is_video = strpos( $mime, 'video/' ) === 0;

		// Create WP attachment.
		$attachment_id = wp_insert_attachment(
			array(
				'post_mime_type' => $mime,
				'post_title'     => sanitize_file_name( $file['name'] ),
				'post_status'    => 'inherit',
			),
			$upload_data['file']
		);

		if ( $attachment_id && ! is_wp_error( $attachment_id ) ) {
			$attach_data = wp_generate_attachment_metadata( $attachment_id, $upload_data['file'] );
			wp_update_attachment_metadata( $attachment_id, $attach_data );
		}

		$product_id = absint( $request->get_param( 'product_id' ) );
		$status     = sanitize_key( $request->get_param( 'status' ) );
		if ( ! in_array( $status, array( 'approved', 'pending' ), true ) ) {
			$status = 'approved';
		}

		// Create a new review with this media.
		global $wpdb;
		$reviews_table = $wpdb->prefix . 'ugcify_reviews';

		$review_type = $is_video ? 'video' : 'image';

		$wpdb->insert(
			$reviews_table,
			array(
				'product_id' => $product_id,
				'user_id'    => get_current_user_id(),
				'content'    => '',
				'rating'     => 0,
				'status'     => $status,
				'type'       => $review_type,
				'created_at' => current_time( 'mysql', true ),
				'updated_at' => current_time( 'mysql', true ),
			),
			array( '%d', '%d', '%s', '%d', '%s', '%s', '%s', '%s' )
		);

		$review_id = $wpdb->insert_id;

		if ( ! $review_id ) {
			return new WP_Error(
				'create_failed',
				__( 'Failed to create review entry.', 'ugcify' ),
				array( 'status' => 500 )
			);
		}

		// Store media URL in review meta.
		$meta_table = $wpdb->prefix . 'ugcify_review_meta';
		$meta_key   = $is_video ? 'videos' : 'images';

		$wpdb->insert(
			$meta_table,
			array(
				'review_id' => $review_id,
				'meta_key'  => $meta_key,
				'meta_value' => maybe_serialize( array( $file_url ) ),
			),
			array( '%d', '%s', '%s' )
		);

		$row           = (object) array(
			'id'         => $review_id,
			'product_id' => $product_id,
			'user_id'    => get_current_user_id(),
			'guest_name' => '',
			'rating'     => 0,
			'content'    => '',
			'type'       => $review_type,
			'status'     => $status,
			'created_at' => current_time( 'mysql', true ),
		);

		return rest_ensure_response(
			array(
				'success' => true,
				'item'    => $this->format_item( $row ),
			)
		);
	}

	// ─────────────────────────────────────────────────────────────────
	// GET /library/products
	// ─────────────────────────────────────────────────────────────────

	/**
	 * Return distinct products that have at least one UGC review with media.
	 *
	 * @param WP_REST_Request $request Request.
	 * @return \WP_REST_Response
	 */
	public function get_products( WP_REST_Request $request ) {
		global $wpdb;

		$reviews_table = $wpdb->prefix . 'ugcify_reviews';
		$meta_table    = $wpdb->prefix . 'ugcify_review_meta';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
		$rows = $wpdb->get_results(
			"SELECT DISTINCT r.product_id
			FROM {$reviews_table} AS r
			INNER JOIN {$meta_table} AS rm ON r.id = rm.review_id AND rm.meta_key IN ('images','videos')
			WHERE r.product_id > 0
			ORDER BY r.product_id ASC
			LIMIT 200"
		);

		$products = array();
		foreach ( $rows as $row ) {
			$pid = (int) $row->product_id;
			if ( $pid <= 0 ) {
				continue;
			}

			$name = '';
			if ( function_exists( 'wc_get_product' ) ) {
				$product = wc_get_product( $pid );
				if ( $product ) {
					$name = $product->get_name();
				}
			}

			if ( ! $name ) {
				$name = get_the_title( $pid );
			}

			if ( $name ) {
				$products[] = array(
					'id'   => $pid,
					'name' => $name,
				);
			}
		}

		return rest_ensure_response(
			array(
				'success'  => true,
				'products' => $products,
			)
		);
	}
}
