<?php
namespace SabaiApps\Directories\Component\WordPressContent\SystemTool;

use SabaiApps\Directories\Component\System\Tool\AbstractTool;
use SabaiApps\Directories\Context;

class CleanUnattachedMediaFilesSystemTool extends AbstractTool {

	protected function _systemToolInfo() {
		return array(
			'label'       => __( 'Clean unattached media files', 'directories-pro' ),
			'description' => __( 'This tool finds unattached WordPress media files and either assigns them a post if in use or removes them if unused.', 'directories-pro' ),
			'weight'      => 60,
		);
	}

	public function systemToolSettingsForm( $step, array $values, array $parents = array(), ?Context $context = null ) {
		$form = array(
			'num'    => array(
				'#type'          => 'number',
				'#title'         => __( 'Number of items to process per request', 'directories-pro' ),
				'#horizontal'    => true,
				'#default_value' => 50,
				'#min_value'     => 1,
				'#max_value'     => 100,
				'#integer'       => true,
				'#required'      => true,
			),
			'delete' => array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Delete unattached media files', 'directories-pro' ),
				'#description'   => __( 'Unattached media files may still be used by certain plugins, so make sure you know what you are doing.', 'directories-pro' ),
				'#horizontal'    => true,
				'#default_value' => false,
			),
		);

		return $form;
	}

	public function systemToolInit( array $settings, array &$storage, array &$logs, ?Context $context = null ) {
		global $wpdb;
		$tasks = array();
		foreach ( array( 'image', 'file' ) as $task ) {
			$sql = sprintf(
				'SELECT COUNT(DISTINCT(p.ID))
    FROM %1$sposts AS p
    WHERE p.post_type = \'attachment\'
    AND (p.post_mime_type %2$s LIKE \'image%%\')
    AND p.post_parent = 0',
				$wpdb->prefix,
				$task === 'image' ? '' : 'NOT'
			);
			if ( $count = $wpdb->get_var( $sql ) ) {
				$tasks[ $task ] = $count;
			}
		}
		foreach ( array( 'image', 'file' ) as $task ) {
			$sql = sprintf(
				'SELECT COUNT(DISTINCT(p.ID))
    FROM %1$sposts AS p 
    LEFT JOIN %1$sposts AS p2 ON p2.ID = p.post_parent
    WHERE p.post_type = \'attachment\'
    AND (p.post_mime_type %2$s LIKE \'image%%\')
    AND p.post_parent > 0
    AND p2.ID IS NULL',
				$wpdb->prefix,
				$task === 'image' ? '' : 'NOT'
			);
			if ( $count = $wpdb->get_var( $sql ) ) {
				$tasks[ $task . '_orphaned' ] = $count;
			}
		}
		return $tasks;
	}

	public function systemToolRunTask( $task, array $settings, $iteration, $total, array &$storage, array &$logs, ?Context $context = null ) {
		global $wpdb;
		$offset         = ( $iteration - 1 ) * $settings['num'];
		$attachment_ids = array();
		switch ( $task ) {
			case 'image':
			case 'file':
				$type           = $task;
				$sql            = sprintf(
					'SELECT DISTINCT(p.ID)
    FROM %1$sposts AS p
    WHERE p.post_type = \'attachment\'
    AND (p.post_mime_type %2$s LIKE \'image%%\')
    AND p.post_parent = 0
    LIMIT %3$d OFFSET %4$d',
					$wpdb->prefix,
					$type === 'image' ? '' : 'NOT',
					$settings['num'],
					$offset
				);
				$attachment_ids = $wpdb->get_col( $sql );
				if ( is_array( $attachment_ids ) && ! empty( $attachment_ids ) ) {
					$logs['info'][] = sprintf(
						'Found unattached media files (type: %s). ID: %s',
						$type,
						implode( ', ', $attachment_ids )
					);
				}
				break;
			case 'image_orphaned':
			case 'file_orphaned':
				$type           = $task === 'image_orphaned' ? 'image' : 'file';
				$sql            = sprintf(
					'SELECT DISTINCT(p.ID)
    FROM %1$sposts AS p
    LEFT JOIN %1$sposts AS p2 ON p2.ID = p.post_parent
    WHERE p.post_type = \'attachment\'
    AND (p.post_mime_type %2$s LIKE \'image%%\')
    AND p.post_parent > 0
    AND p2.ID IS NULL
    LIMIT %3$d OFFSET %4$d',
					$wpdb->prefix,
					$type === 'image' ? '' : 'NOT',
					$settings['num'],
					$offset
				);
				$attachment_ids = $wpdb->get_col( $sql );
				if ( is_array( $attachment_ids ) && ! empty( $attachment_ids ) ) {
					$logs['info'][] = sprintf(
						'Found orphaned media files (type: %s). ID: %s',
						$type,
						implode( ', ', $attachment_ids )
					);
				}
				break;
			default:
		}

		if ( ! is_array( $attachment_ids ) || empty( $attachment_ids ) ) {
			return 1;
		}

		$attachment_ids_str = implode( ', ', $attachment_ids );
		if ( $type === 'image' ) {
			// Exclude WordPress featured images
			$sql = sprintf(
				'SELECT DISTINCT(meta_value)
    FROM %1$spostmeta
    WHERE meta_key = \'_thumbnail_id\'
    AND meta_value IN (%2$s)',
				$wpdb->prefix,
				$attachment_ids_str
			);
			if ( $featured_attachment_ids = $wpdb->get_col( $sql ) ) {
				$attachment_ids     = array_diff( $attachment_ids, $featured_attachment_ids );
				$attachment_ids_str = implode( ', ', $attachment_ids );
				$logs['info'][]     = sprintf(
					'Media files (ID: %s) are unattached but used as featured images.',
					implode( ', ', $featured_attachment_ids )
				);
			}
		}

		$sql                 = sprintf(
			'SELECT entity_type, bundle_name, entity_id, field_name, attachment_id
    FROM %1$sentity_field_wp_file 
    WHERE attachment_id IN (%2$s)',
			$this->_application->getDB()->getResourcePrefix(),
			$attachment_ids_str
		);
		$used_attachment_ids = array();
		foreach ( $this->_application->getDB()->query( $sql ) as $row ) {
			if ( $row['entity_type'] === 'post' ) {
				if ( false === get_post_status( $row['entity_id'] ) ) {
					continue;
				}

				wp_update_post(
					array(
						'ID'          => $row['attachment_id'],
						'post_parent' => $row['entity_id'],
					)
				);
				$logs['success'][] = sprintf(
					'Media file (ID: %d) attached to post (ID: %d, Field: %s).',
					$row['attachment_id'],
					$row['entity_id'],
					$row['field_name']
				);
			} else {
				$logs['info'][] = sprintf(
					'Media file (ID: %d) is unattached but used by %s (ID: %d, Field: %s).',
					$row['attachment_id'],
					$row['entity_type'],
					$row['entity_id'],
					$row['field_name']
				);
			}
			update_post_meta( $row['attachment_id'], '_drts_entity_type', $row['entity_type'] );
			update_post_meta( $row['attachment_id'], '_drts_entity_id', $row['entity_id'] );
			update_post_meta( $row['attachment_id'], '_drts_field', $row['field_name'] );
			$used_attachment_ids[] = $row['attachment_id'];
		}

		// Delete unused attachments?
		if ( ! empty( $settings['delete'] ) ) {
			$deleted_attachment_ids = array();
			foreach ( array_diff( $attachment_ids, $used_attachment_ids ) as $orphan_attachment_id ) {
				if ( wp_delete_attachment( $orphan_attachment_id, true ) ) {
					$deleted_attachment_ids[] = $orphan_attachment_id;
				} else {
					$logs['error'][] = sprintf(
						'Failed deleting unattached media file. ID: %d',
						$orphan_attachment_id
					);
				}
			}
			if ( ! empty( $deleted_attachment_ids ) ) {
				$logs['success'][] = sprintf(
					'Deleted unattached media files. ID: %s',
					implode( ', ', $deleted_attachment_ids )
				);
			}
		}

		return $count;
	}
}
