<?php

namespace MediaTrim\Core;

use MediaTrim\Traits\Singleton;

defined('ABSPATH') || exit;

/**
 * Class Trash
 *
 * Handles trash management for Media Trim - move files to trash instead of permanent delete.
 *
 * @package MediaTrim\Core
 */
class Trash
{
    use Singleton;

    /**
     * Trash directory path
     *
     * @var string
     */
    private $trash_dir;

    /**
     * Trash items table name
     *
     * @var string
     */
    private $table_name;

    /**
     * Constructor
     */
    public function __construct()
    {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'mtrim_trash_items';
        $upload_dir = wp_upload_dir();
        $this->trash_dir = $upload_dir['basedir'] . '/media-trim-trash/';

        $this->init_hooks();
    }

    /**
     * Initialize hooks
     */
    public function init_hooks()
    {
        add_action('wp_ajax_mtrim_move_to_trash', [$this, 'ajax_move_to_trash']);
        add_action('wp_ajax_mtrim_restore_from_trash', [$this, 'ajax_restore_from_trash']);
        add_action('wp_ajax_mtrim_delete_permanently', [$this, 'ajax_delete_permanently']);
        add_action('wp_ajax_mtrim_empty_trash', [$this, 'ajax_empty_trash']);
        add_action('wp_ajax_mtrim_get_trash_items', [$this, 'ajax_get_trash_items']);
        add_action('wp_ajax_mtrim_bulk_restore_from_trash', [$this, 'ajax_bulk_restore_from_trash']);
        add_action('wp_ajax_mtrim_bulk_delete_permanently', [$this, 'ajax_bulk_delete_permanently']);
        add_action('wp_ajax_mtrim_get_trash_dates', [$this, 'ajax_get_trash_dates']);
    }

    /**
     * Ensure trash directory exists
     *
     * @return bool
     */
    private function ensure_trash_dir()
    {
        if (!file_exists($this->trash_dir)) {
            return wp_mkdir_p($this->trash_dir);
        }
        return true;
    }

    /**
     * AJAX handler to move media to trash
     */
    public function ajax_move_to_trash()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $attachment_id = isset($_POST['attachment_id']) ? absint($_POST['attachment_id']) : 0;

        if (!$attachment_id) {
            wp_send_json_error(['message' => __('Invalid attachment ID', 'media-trim')]);
        }

        $result = $this->move_to_trash($attachment_id);

        if ($result) {
            wp_send_json_success(['message' => __('File moved to trash', 'media-trim')]);
        } else {
            wp_send_json_error(['message' => __('Failed to move file to trash', 'media-trim')]);
        }
    }

    /**
     * Move a media file to trash
     *
     * @param int $attachment_id The attachment ID.
     * @return bool
     */
    public function move_to_trash($attachment_id)
    {
        global $wpdb;

        if (!$this->ensure_trash_dir()) {
            return false;
        }

        $original_path = get_attached_file($attachment_id);
        if (!$original_path || !file_exists($original_path)) {
            return false;
        }

        // Get relative path from uploads directory
        $upload_dir = wp_upload_dir();
        $relative_path = str_replace($upload_dir['basedir'] . '/', '', $original_path);

        // Create trash path preserving directory structure
        $trash_path = $this->trash_dir . $relative_path;
        $trash_dir = dirname($trash_path);

        if (!file_exists($trash_dir)) {
            wp_mkdir_p($trash_dir);
        }

        // Get file info before moving
        $file_size = filesize($original_path);
        $file_info = pathinfo($original_path);

        // Move main file.
        global $wp_filesystem;
        if ( empty( $wp_filesystem ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
            WP_Filesystem();
        }
        if ( ! $wp_filesystem->move( $original_path, $trash_path, true ) ) {
            return false;
        }

        // Move thumbnails/resized versions
        $metadata = wp_get_attachment_metadata($attachment_id);
        if (!empty($metadata['sizes'])) {
            $file_dir = dirname($original_path);
            foreach ($metadata['sizes'] as $size => $size_data) {
                $thumb_path = $file_dir . '/' . $size_data['file'];
                if (file_exists($thumb_path)) {
                    $thumb_trash_path = dirname($trash_path) . '/' . $size_data['file'];
                    $wp_filesystem->move( $thumb_path, $thumb_trash_path, true );
                }
            }
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->insert(
            $this->table_name,
            [
                'original_attachment_id' => $attachment_id,
                'original_path' => $original_path,
                'trash_path' => $trash_path,
                'file_name' => $file_info['basename'],
                'file_size' => $file_size,
                'mime_type' => get_post_mime_type($attachment_id),
                'trashed_at' => current_time('mysql'),
            ],
            ['%d', '%s', '%s', '%s', '%d', '%s', '%s']
        );

        // Delete from WordPress media library
        wp_delete_attachment($attachment_id, true);

        return true;
    }

    /**
     * AJAX handler to restore from trash
     */
    public function ajax_restore_from_trash()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $trash_id = isset($_POST['trash_id']) ? absint($_POST['trash_id']) : 0;

        if (!$trash_id) {
            wp_send_json_error(['message' => __('Invalid trash ID', 'media-trim')]);
        }

        $result = $this->restore_from_trash($trash_id);

        if ($result) {
            wp_send_json_success(['message' => __('File restored successfully', 'media-trim')]);
        } else {
            wp_send_json_error(['message' => __('Failed to restore file', 'media-trim')]);
        }
    }

    /**
     * Restore a file from trash
     *
     * @param int $trash_id The trash item ID.
     * @return bool|int New attachment ID on success, false on failure.
     */
    public function restore_from_trash($trash_id)
    {
        global $wpdb;

        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $item = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->table_name} WHERE id = %d",
            $trash_id
        ));
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

        if (!$item || !file_exists($item->trash_path)) {
            return false;
        }

        // Ensure original directory exists
        $original_dir = dirname($item->original_path);
        if (!file_exists($original_dir)) {
            wp_mkdir_p($original_dir);
        }

        // Move file back.
        global $wp_filesystem;
        if ( empty( $wp_filesystem ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
            WP_Filesystem();
        }
        if ( ! $wp_filesystem->move( $item->trash_path, $item->original_path, true ) ) {
            return false;
        }

        // Move thumbnails back
        $trash_dir = dirname($item->trash_path);
        $original_file_dir = dirname($item->original_path);
        $base_name = pathinfo($item->file_name, PATHINFO_FILENAME);

        // Find and move related thumbnails
        $trash_files = glob($trash_dir . '/' . $base_name . '-*');
        if ($trash_files) {
            foreach ($trash_files as $thumb_trash_path) {
                $thumb_name = basename($thumb_trash_path);
                $thumb_original_path = $original_file_dir . '/' . $thumb_name;
                $wp_filesystem->move( $thumb_trash_path, $thumb_original_path, true );
            }
        }

        // Re-add to media library
        $attachment_id = wp_insert_attachment([
            'post_mime_type' => $item->mime_type,
            'post_title' => pathinfo($item->file_name, PATHINFO_FILENAME),
            'post_content' => '',
            'post_status' => 'inherit',
        ], $item->original_path);

        if ( $attachment_id && ! is_wp_error( $attachment_id ) ) {
            require_once ABSPATH . 'wp-admin/includes/image.php';
            $metadata = wp_generate_attachment_metadata( $attachment_id, $item->original_path );
            wp_update_attachment_metadata( $attachment_id, $metadata );

            // Remove from trash table.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->delete( $this->table_name, [ 'id' => $trash_id ], [ '%d' ] );

            return $attachment_id;
        }

        return false;
    }

    /**
     * AJAX handler to delete permanently
     */
    public function ajax_delete_permanently()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $trash_id = isset($_POST['trash_id']) ? absint($_POST['trash_id']) : 0;

        if (!$trash_id) {
            wp_send_json_error(['message' => __('Invalid trash ID', 'media-trim')]);
        }

        $result = $this->delete_permanently($trash_id);

        if ($result) {
            wp_send_json_success(['message' => __('File deleted permanently', 'media-trim')]);
        } else {
            wp_send_json_error(['message' => __('Failed to delete file', 'media-trim')]);
        }
    }

    /**
     * Permanently delete a trash item
     *
     * @param int $trash_id The trash item ID.
     * @return bool
     */
    public function delete_permanently($trash_id)
    {
        global $wpdb;

        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $item = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->table_name} WHERE id = %d",
            $trash_id
        ));
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

        if (!$item) {
            return false;
        }

        // Delete main file
        if (file_exists($item->trash_path)) {
            wp_delete_file($item->trash_path);
        }

        // Delete thumbnails
        $trash_dir = dirname($item->trash_path);
        $base_name = pathinfo($item->file_name, PATHINFO_FILENAME);
        $trash_files = glob($trash_dir . '/' . $base_name . '-*');
        if ($trash_files) {
            foreach ($trash_files as $file) {
                wp_delete_file($file);
            }
        }

        // Remove from database
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->delete($this->table_name, ['id' => $trash_id], ['%d']);

        return true;
    }

    /**
     * AJAX handler to empty trash
     */
    public function ajax_empty_trash()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $result = $this->empty_trash();

        wp_send_json_success([
            /* translators: %d: number of items deleted */
            'message' => sprintf(__('%d items deleted permanently', 'media-trim'), $result),
            'deleted' => $result,
        ]);
    }

    /**
     * Empty all items from trash
     *
     * @return int Number of items deleted.
     */
    public function empty_trash()
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is safely constructed.
        $items = $wpdb->get_results("SELECT * FROM {$this->table_name}");
        $deleted = 0;

        foreach ($items as $item) {
            if ($this->delete_permanently($item->id)) {
                $deleted++;
            }
        }

        return $deleted;
    }

    /**
     * AJAX handler to get trash items
     */
    public function ajax_get_trash_items()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $page = isset($_POST['page']) ? absint($_POST['page']) : 1;
        $limit = isset($_POST['limit']) ? absint($_POST['limit']) : 20;
        $search = isset($_POST['search']) ? sanitize_text_field(wp_unslash($_POST['search'])) : '';
        $mtrim_date = isset($_POST['mtrim_date']) ? sanitize_text_field(wp_unslash($_POST['mtrim_date'])) : '';

        $results = $this->get_trash_items($page, $limit, $search, $mtrim_date);

        wp_send_json_success($results);
    }

    /**
     * AJAX handler to get unique months for trashed items
     */
    public function ajax_get_trash_dates()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $results = $wpdb->get_results("SELECT DISTINCT DATE_FORMAT(trashed_at, '%Y-%m') as value FROM $this->table_name ORDER BY trashed_at DESC");

        $dates = [];
        foreach ($results as $res) {
            if (!$res->value) continue;
            $dates[] = [
                'value' => $res->value,
                'label' => date_i18n('F Y', strtotime($res->value . '-01'))
            ];
        }

        wp_send_json_success($dates);
    }

    /**
     * Get all items in trash
     *
     * @return array
     */
    public function get_trash_items($page = 1, $limit = 20, $search = '', $mtrim_date = '')
    {
        global $wpdb;
        $offset = ($page - 1) * $limit;

        $where = "WHERE 1=1";
        $params = [];

        if (!empty($search)) {
            $where .= " AND (file_name LIKE %s OR original_path LIKE %s OR original_attachment_id = %d)";
            $params[] = '%' . $wpdb->esc_like($search) . '%';
            $params[] = '%' . $wpdb->esc_like($search) . '%';
            $params[] = is_numeric($search) ? (int) $search : 0;
        }

        if (!empty($mtrim_date)) {
            $where .= " AND trashed_at LIKE %s";
            $params[] = $mtrim_date . '%';
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is safely constructed from $wpdb->prefix.
        $count_sql = "SELECT COUNT(*) FROM {$this->table_name} $where";
        if (!empty($params)) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Query uses prepare() with placeholders.
            $total = $wpdb->get_var($wpdb->prepare($count_sql, $params));
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- No user input when params is empty.
            $total = $wpdb->get_var($count_sql);
        }

        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $sql = "SELECT * FROM {$this->table_name} $where ORDER BY trashed_at DESC LIMIT %d, %d";
        $final_params = array_merge($params, [$offset, $limit]);
        $items = $wpdb->get_results($wpdb->prepare($sql, $final_params));
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

        foreach ($items as &$item) {
            $item->formatted_size = size_format($item->file_size);
            $item->trashed_date = date_i18n(get_option('date_format'), strtotime($item->trashed_at));

            // Get thumbnail URL from trash
            if (file_exists($item->trash_path)) {
                $item->is_image = wp_match_mime_types('image', $item->mime_type);
                if ($item->is_image) {
                    $upload_dir = wp_upload_dir();
                    $base_url = $upload_dir['baseurl'] . '/media-trim-trash/';
                    $relative_path = str_replace($this->trash_dir, '', $item->trash_path);
                    $item->url = $base_url . $relative_path;
                }
            }
        }

        return [
            'items' => $items,
            'total' => (int) $total,
            'pages' => ceil($total / $limit),
            'page'  => $page
        ];
    }

    /**
     * AJAX handler for bulk restore
     */
    public function ajax_bulk_restore_from_trash()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $json_ids  = isset( $_POST['trash_ids'] ) ? wp_unslash( $_POST['trash_ids'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We're json_decoding it later.
        $trash_ids = json_decode( $json_ids, true );
        $trash_ids = is_array( $trash_ids ) ? array_map( 'absint', $trash_ids ) : [];

        if ( empty( $trash_ids ) ) {
            wp_send_json_error( [ 'message' => __( 'No items selected', 'media-trim' ) ] );
        }

        $restored = 0;
        foreach ( $trash_ids as $trash_id ) {
            $result = $this->restore_from_trash( $trash_id );
            if ( $result && ! is_wp_error( $result ) ) {
                $restored++;
            }
        }

        wp_send_json_success([
            /* translators: %d: number of restored items */
            'message' => sprintf(__('%d items restored successfully', 'media-trim'), $restored)
        ]);
    }

    /**
     * AJAX handler for bulk permanent delete
     */
    public function ajax_bulk_delete_permanently()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Unauthorized', 'media-trim')]);
        }

        $json_ids  = isset( $_POST['trash_ids'] ) ? wp_unslash( $_POST['trash_ids'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We're json_decoding it later.
        $trash_ids = json_decode( $json_ids, true );
        $trash_ids = is_array( $trash_ids ) ? array_map( 'absint', $trash_ids ) : [];

        if ( empty( $trash_ids ) ) {
            wp_send_json_error( [ 'message' => __( 'No items selected', 'media-trim' ) ] );
        }

        $deleted = 0;
        foreach ( $trash_ids as $trash_id ) {
            if ( $this->delete_permanently( $trash_id ) ) {
                $deleted++;
            }
        }

        wp_send_json_success([
            /* translators: %d: number of permanently deleted items */
            'message' => sprintf(__('%d items deleted permanently', 'media-trim'), $deleted)
        ]);
    }

    /**
     * Get trash statistics
     */
    public function get_trash_stats()
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is safely constructed.
        $count = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name}");
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is safely constructed.
        $size = $wpdb->get_var("SELECT SUM(file_size) FROM {$this->table_name}");

        return [
            'count' => (int) $count,
            'size' => (int) $size,
            'formatted_size' => size_format($size ?: 0),
        ];
    }
}
