<?php

namespace Limb_Chatbot\Includes\Repositories;

use Limb_Chatbot\Includes\Data_Objects\File;
use Limb_Chatbot\Includes\Services\Collection;

/**
 * Repository for managing File data objects.
 *
 * Handles retrieval and filtering of files stored in WordPress options.
 * Files are stored in a single option as an array and managed through
 * the File data object class.
 *
 * @package Limb_Chatbot\Includes\Repositories
 * @since 1.0.0
 */
class File_Repository {

	/**
	 * Retrieves a collection of files based on given parameters.
	 *
	 * Supports search filtering and pagination. Files are retrieved from
	 * the WordPress options table and filtered based on the parameters.
	 *
	 * @param  array  $params  {
	 *     Optional. Parameters for filtering and pagination.
	 *
	 *     @type string   $search         Search keyword to match against file names.
	 *     @type string[] $search_fields  Fields to apply the search against (e.g., 'file_name', 'original_name').
	 *     @type int      $per_page       Number of results per page. Default 10.
	 *     @type int      $page           Current page number. Default 1.
	 *     @type string   $orderby        Field to order by. Default 'created_at'.
	 *     @type string   $order          Sort order direction. Accepts 'ASC' or 'DESC'. Default 'DESC'.
	 *     @type string   $status         Filter by file status (e.g., 'uploaded', 'active', 'failed').
	 *     @type string[] $uuids          Filter by specific file UUIDs.
	 * }
	 *
	 * @return Collection Collection of File objects.
	 * @since 1.0.0
	 */
	public function get_items( array $params = [] ): Collection {
		$files = File::get_all_as_objects();

		// Filter by search if provided
		if ( ! empty( $params['search'] ) ) {
			$search_term = strtolower( trim( $params['search'] ) );
			// Default search fields if not specified
			$search_fields = $params['search_fields'] ?? [ 'original_name', 'file_name' ];
			
			if ( ! is_array( $search_fields ) ) {
				$search_fields = [ $search_fields ];
			}

			$files = array_filter( $files, function ( File $file ) use ( $search_term, $search_fields ) {
				foreach ( $search_fields as $field ) {
					$method = 'get_' . $field;
					if ( method_exists( $file, $method ) ) {
						$value = $file->$method();
						if ( is_string( $value ) && stripos( strtolower( $value ), $search_term ) !== false ) {
							return true;
						}
					}
				}
				return false;
			} );
		}

		// Filter by status if provided
		if ( ! empty( $params['status'] ) ) {
			$files = array_filter( $files, function ( $file ) use ( $params ) {
				return $file->get_status() === $params['status'];
			} );
		}

		// Filter by UUIDs if provided
		if ( ! empty( $params['uuids'] ) && is_array( $params['uuids'] ) ) {
			$uuids = $params['uuids'];
			$files = array_filter( $files, function ( $file ) use ( $uuids ) {
				return in_array( $file->get_uuid(), $uuids, true );
			} );
		}

		// Filter by external provider if provided
		if ( ! empty( $params['external_provider'] ) ) {
			$external_provider = $params['external_provider'];
			$files             = array_filter( $files, function ( File $file ) use ( $external_provider ) {
				return $file->get_meta( 'external_provider' ) === $external_provider;
			} );
		}

		// Apply sorting
		$orderby = $params['orderby'] ?? 'created_at';
		$order   = strtolower( $params['order'] ?? 'desc' );

		usort( $files, function ( $a, $b ) use ( $orderby, $order ) {
			$method = 'get_' . $orderby;

			// Handle different field types
			if ( method_exists( $a, $method ) && method_exists( $b, $method ) ) {
				$value_a = $a->$method();
				$value_b = $b->$method();

				// Handle date fields
				if ( $orderby === 'created_at' ) {
					$value_a = strtotime( $value_a );
					$value_b = strtotime( $value_b );
				}

				// Handle numeric fields
				if ( $orderby === 'file_size' ) {
					$value_a = (int) $value_a;
					$value_b = (int) $value_b;
				}

				// Handle string fields
				if ( is_string( $value_a ) && is_string( $value_b ) ) {
					$value_a = strtolower( $value_a );
					$value_b = strtolower( $value_b );
				}

				if ( $value_a === $value_b ) {
					return 0;
				}

				$result = $value_a < $value_b ? - 1 : 1;

				return $order === 'asc' ? $result : - $result;
			}

			return 0;
		} );

		$files = array_values( $files );

		// Apply pagination
		$per_page = $params['per_page'] ?? 10;
		$page     = $params['page'] ?? 1;
		$offset   = ( $page - 1 ) * $per_page;

		$total_files     = count( $files );
		$paginated_files = array_slice( $files, $offset, $per_page );

		// Create collection
		$collection = new Collection( $paginated_files );
		$collection->push_property( 'total', $total_files );
		$collection->push_property( 'page', $page );
		$collection->push_property( 'per_page', $per_page );
		$collection->push_property( 'total_pages', ceil( $total_files / $per_page ) );

		return $collection;
	}

	/**
	 * Retrieves a single file by UUID.
	 *
	 * @param  string  $uuid  The file UUID.
	 *
	 * @return File|null The File object or null if not found.
	 * @since 1.0.0
	 */
	public function get_item( string $uuid ): ?File {
		return File::find_by_uuid( $uuid );
	}
}

