<?php

namespace MediaTrim\Core;

use MediaTrim\Traits\Singleton;

defined('ABSPATH') || exit;

/**
 * Class ScanManager
 *
 * Manages scan state for pause/resume capability and scan history logging.
 *
 * @package MediaTrim\Core
 */
class ScanManager
{
    use Singleton;

    /**
     * Scan state table name
     *
     * @var string
     */
    private $state_table;

    /**
     * Scan history table name
     *
     * @var string
     */
    private $history_table;

    /**
     * Constructor
     */
    public function __construct()
    {
        global $wpdb;
        $this->state_table = $wpdb->prefix . 'mtrim_scan_state';
        $this->history_table = $wpdb->prefix . 'mtrim_scan_history';

        $this->init_hooks();
    }

    /**
     * Initialize hooks
     */
    public function init_hooks()
    {
        add_action('wp_ajax_mtrim_pause_scan', [$this, 'ajax_pause_scan']);
        add_action('wp_ajax_mtrim_resume_scan', [$this, 'ajax_resume_scan']);
        add_action('wp_ajax_mtrim_get_scan_state', [$this, 'ajax_get_scan_state']);
        add_action('wp_ajax_mtrim_get_scan_history', [$this, 'ajax_get_scan_history']);
        add_action('wp_ajax_mtrim_cancel_scan', [$this, 'ajax_cancel_scan']);
    }

    /**
     * Save scan state for resume capability
     *
     * @param string $scan_type Type of scan (unused, duplicate, filesystem).
     * @param int $current_offset Current offset in the scan.
     * @param int $total_items Total items to scan.
     * @return bool
     */
    public function save_state($scan_type, $current_offset, $total_items)
    {
        global $wpdb;

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

        $data = [
            'scan_type' => $scan_type,
            'current_offset' => $current_offset,
            'total_items' => $total_items,
            'status' => 'running',
            'started_at' => current_time('mysql'),
        ];

        if ($existing) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                $this->state_table,
                $data,
                ['id' => $existing->id],
                ['%s', '%d', '%d', '%s', '%s'],
                ['%d']
            );
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $wpdb->insert(
                $this->state_table,
                $data,
                ['%s', '%d', '%d', '%s', '%s']
            );
        }

        return true;
    }

    /**
     * Get current scan state
     *
     * @param string $scan_type Type of scan.
     * @return object|null
     */
    public function get_state($scan_type)
    {
        global $wpdb;

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

    /**
     * Pause a running scan
     *
     * @param string $scan_type Type of scan.
     * @return bool
     */
    public function pause_scan($scan_type)
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->update(
            $this->state_table,
            [
                'status' => 'paused',
                'paused_at' => current_time('mysql'),
            ],
            ['scan_type' => $scan_type],
            ['%s', '%s'],
            ['%s']
        );
    }

    /**
     * Resume a paused scan
     *
     * @param string $scan_type Type of scan.
     * @return object|null Scan state with resume offset.
     */
    public function resume_scan($scan_type)
    {
        global $wpdb;

        $state = $this->get_state($scan_type);

        if ($state && $state->status === 'paused') {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                $this->state_table,
                ['status' => 'running'],
                ['scan_type' => $scan_type],
                ['%s'],
                ['%s']
            );
            return $state;
        }

        return null;
    }

    /**
     * Complete a scan and clear state
     *
     * @param string $scan_type Type of scan.
     * @param array $results Scan results summary.
     * @return bool
     */
    public function complete_scan($scan_type, $results = [])
    {
        global $wpdb;

        $state = $this->get_state($scan_type);

        // Log to history
        if ($state) {
            $this->log_scan_history([
                'scan_type' => $scan_type,
                'items_scanned' => $state->total_items,
                'unused_found' => isset($results['found']) ? $results['found'] : 0,
                'completed_at' => current_time('mysql'),
                'duration' => strtotime(current_time('mysql')) - strtotime($state->started_at),
            ]);
        }

        // Clear state
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->delete($this->state_table, ['scan_type' => $scan_type], ['%s']);

        return true;
    }

    /**
     * Cancel a scan
     *
     * @param string $scan_type Type of scan.
     * @return bool
     */
    public function cancel_scan($scan_type)
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->delete($this->state_table, ['scan_type' => $scan_type], ['%s']);
    }

    /**
     * Log scan to history
     *
     * @param array $data Scan history data.
     * @return bool
     */
    public function log_scan_history($data)
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        return $wpdb->insert(
            $this->history_table,
            [
                'scan_type' => $data['scan_type'],
                'items_scanned' => $data['items_scanned'],
                'unused_found' => $data['unused_found'],
                'completed_at' => $data['completed_at'],
                'duration' => $data['duration'],
            ],
            ['%s', '%d', '%d', '%s', '%d']
        );
    }

    /**
     * Get scan history
     *
     * @param int $limit Number of records to retrieve.
     * @return array
     */
    public function get_history($limit = 20)
    {
        global $wpdb;

        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $items = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$this->history_table} ORDER BY completed_at DESC LIMIT %d",
            $limit
        ));
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

        foreach ($items as &$item) {
            $item->formatted_date = date_i18n(
                get_option('date_format') . ' ' . get_option('time_format'),
                strtotime($item->completed_at)
            );
            $item->formatted_duration = $this->format_duration($item->duration);
            $item->scan_type_label = $this->get_scan_type_label($item->scan_type);
        }

        return $items;
    }

    /**
     * Format duration in human-readable format
     *
     * @param int $seconds Duration in seconds.
     * @return string
     */
    private function format_duration($seconds)
    {
        if ($seconds < 60) {
            /* translators: %d: number of seconds */
            return sprintf(__('%d seconds', 'media-trim'), $seconds);
        } elseif ($seconds < 3600) {
            $minutes = floor($seconds / 60);
            /* translators: %d: number of minutes */
            return sprintf(__('%d minutes', 'media-trim'), $minutes);
        } else {
            $hours = floor($seconds / 3600);
            $minutes = floor(($seconds % 3600) / 60);
            /* translators: %1$d: number of hours, %2$d: number of minutes */
            return sprintf(__('%1$d hours %2$d minutes', 'media-trim'), $hours, $minutes);
        }
    }

    /**
     * Get human-readable label for scan type
     *
     * @param string $scan_type Scan type.
     * @return string
     */
    private function get_scan_type_label($scan_type)
    {
        $labels = [
            'unused' => __('Unused Media Scan', 'media-trim'),
            'duplicate' => __('Duplicate Scan', 'media-trim'),
            'filesystem' => __('Filesystem Scan', 'media-trim'),
        ];

        return isset($labels[$scan_type]) ? $labels[$scan_type] : $scan_type;
    }

    /**
     * AJAX handler to pause scan
     */
    public function ajax_pause_scan()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

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

        $scan_type = isset($_POST['scan_type']) ? sanitize_text_field(wp_unslash($_POST['scan_type'])) : '';

        if (empty($scan_type)) {
            wp_send_json_error(['message' => __('Invalid scan type', 'media-trim')]);
        }

        $this->pause_scan($scan_type);

        wp_send_json_success([
            'message' => __('Scan paused successfully', 'media-trim'),
            'state' => $this->get_state($scan_type),
        ]);
    }

    /**
     * AJAX handler to resume scan
     */
    public function ajax_resume_scan()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

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

        $scan_type = isset($_POST['scan_type']) ? sanitize_text_field(wp_unslash($_POST['scan_type'])) : '';

        if (empty($scan_type)) {
            wp_send_json_error(['message' => __('Invalid scan type', 'media-trim')]);
        }

        $state = $this->resume_scan($scan_type);

        if ($state) {
            wp_send_json_success([
                'message' => __('Scan resumed', 'media-trim'),
                'resume_offset' => $state->current_offset,
                'total_items' => $state->total_items,
            ]);
        } else {
            wp_send_json_error(['message' => __('No paused scan found', 'media-trim')]);
        }
    }

    /**
     * AJAX handler to get scan state
     */
    public function ajax_get_scan_state()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

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

        $scan_type = isset($_POST['scan_type']) ? sanitize_text_field(wp_unslash($_POST['scan_type'])) : '';

        $state = $this->get_state($scan_type);

        wp_send_json_success($state);
    }

    /**
     * AJAX handler to get scan history
     */
    public function ajax_get_scan_history()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

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

        $limit = isset($_POST['limit']) ? absint($_POST['limit']) : 20;

        $history = $this->get_history($limit);

        wp_send_json_success($history);
    }

    /**
     * AJAX handler to cancel scan
     */
    public function ajax_cancel_scan()
    {
        check_ajax_referer('mtrim_admin_nonce', 'nonce');

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

        $scan_type = isset($_POST['scan_type']) ? sanitize_text_field(wp_unslash($_POST['scan_type'])) : '';

        if (empty($scan_type)) {
            wp_send_json_error(['message' => __('Invalid scan type', 'media-trim')]);
        }

        $this->cancel_scan($scan_type);

        wp_send_json_success(['message' => __('Scan cancelled', 'media-trim')]);
    }
}
