<?php
/**
 * Plugin Name: Smart Image Resizer
 * Description: Resize Media Library images into admin-defined presets, bulk-generate copies, and optionally create WebP versions while keeping originals safe by default.
 * Version: 0.1.0
 * Author: Flatlogic AI
 * Requires at least: 6.0
 * Requires PHP: 8.0
 * Text Domain: smart-image-resizer
 */

if (!defined('ABSPATH')) {
    exit;
}

final class Smart_Image_Resizer {
    const OPTION = 'sir_settings';
    const LOG_OPTION = 'sir_recent_jobs';
    const META_KEY = '_sir_resized_files';
    const NONCE_ACTION = 'sir_admin_action';
    private static $instance = null;

    public static function instance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action('admin_menu', [$this, 'admin_menu']);
        add_action('admin_init', [$this, 'handle_admin_actions']);
        add_action('admin_enqueue_scripts', [$this, 'admin_assets']);
        add_action('add_attachment', [$this, 'resize_on_upload']);
        register_activation_hook(__FILE__, [$this, 'activate']);
    }

    public function activate(): void {
        if (!get_option(self::OPTION)) {
            add_option(self::OPTION, $this->default_settings());
        }
    }

    public function default_settings(): array {
        return [
            'auto_resize' => 1,
            'webp' => 0,
            'keep_original' => 1,
            'presets' => [
                ['name' => 'Card Thumbnail', 'slug' => 'card-thumb', 'width' => 480, 'height' => 320, 'crop' => 1],
                ['name' => 'Content Medium', 'slug' => 'content-medium', 'width' => 960, 'height' => 0, 'crop' => 0],
                ['name' => 'Hero Banner', 'slug' => 'hero-banner', 'width' => 1600, 'height' => 900, 'crop' => 1],
                ['name' => 'Square Social', 'slug' => 'square-social', 'width' => 1080, 'height' => 1080, 'crop' => 1],
            ],
        ];
    }

    public function get_settings(): array {
        $settings = get_option(self::OPTION, []);
        return wp_parse_args(is_array($settings) ? $settings : [], $this->default_settings());
    }

    public function admin_menu(): void {
        add_media_page(
            __('Smart Image Resizer', 'smart-image-resizer'),
            __('Image Resizer', 'smart-image-resizer'),
            'upload_files',
            'smart-image-resizer',
            [$this, 'render_admin_page']
        );
    }

    public function admin_assets(string $hook): void {
        if ($hook !== 'media_page_smart-image-resizer') {
            return;
        }
        wp_enqueue_style('sir-admin', plugin_dir_url(__FILE__) . 'assets/admin.css', [], '0.1.0');
    }

    public function handle_admin_actions(): void {
        if (!is_admin() || empty($_POST['sir_action'])) {
            return;
        }
        if (!current_user_can('upload_files')) {
            wp_die(esc_html__('You do not have permission to resize images.', 'smart-image-resizer'));
        }
        check_admin_referer(self::NONCE_ACTION);
        $action = sanitize_key($_POST['sir_action']);

        if ($action === 'save_settings') {
            $this->save_settings_from_post();
            wp_safe_redirect(add_query_arg(['page' => 'smart-image-resizer', 'sir_notice' => 'settings_saved'], admin_url('upload.php')));
            exit;
        }

        if ($action === 'bulk_resize') {
            $preset_slug = sanitize_title(wp_unslash($_POST['preset_slug'] ?? ''));
            $limit = max(1, min(50, absint($_POST['limit'] ?? 20)));
            $result = $this->bulk_resize($preset_slug, $limit);
            set_transient('sir_last_bulk_result_' . get_current_user_id(), $result, MINUTE_IN_SECONDS * 5);
            wp_safe_redirect(add_query_arg(['page' => 'smart-image-resizer', 'sir_notice' => 'bulk_done'], admin_url('upload.php')));
            exit;
        }
    }

    private function save_settings_from_post(): void {
        $presets = [];
        $names = array_map('sanitize_text_field', wp_unslash($_POST['preset_name'] ?? []));
        $slugs = array_map('sanitize_title', wp_unslash($_POST['preset_slug'] ?? []));
        $widths = array_map('absint', wp_unslash($_POST['preset_width'] ?? []));
        $heights = array_map('absint', wp_unslash($_POST['preset_height'] ?? []));
        $crops = isset($_POST['preset_crop']) ? array_map('absint', wp_unslash($_POST['preset_crop'])) : [];

        for ($i = 0; $i < 6; $i++) {
            $name = trim($names[$i] ?? '');
            $slug = sanitize_title($slugs[$i] ?? $name);
            $width = $widths[$i] ?? 0;
            $height = $heights[$i] ?? 0;
            if (!$name || !$slug || $width < 1) {
                continue;
            }
            $presets[] = [
                'name' => $name,
                'slug' => $slug,
                'width' => $width,
                'height' => $height,
                'crop' => !empty($crops[$i]) ? 1 : 0,
            ];
        }
        if (!$presets) {
            $presets = $this->default_settings()['presets'];
        }

        update_option(self::OPTION, [
            'auto_resize' => !empty($_POST['auto_resize']) ? 1 : 0,
            'webp' => !empty($_POST['webp']) ? 1 : 0,
            'keep_original' => 1,
            'presets' => $presets,
        ]);
    }

    public function render_admin_page(): void {
        $settings = $this->get_settings();
        $presets = array_values($settings['presets']);
        $notice = sanitize_key($_GET['sir_notice'] ?? '');
        $last = get_transient('sir_last_bulk_result_' . get_current_user_id());
        ?>
        <div class="wrap sir-wrap">
            <div class="sir-hero">
                <div>
                    <p class="sir-kicker"><?php esc_html_e('Media performance toolkit', 'smart-image-resizer'); ?></p>
                    <h1><?php esc_html_e('Smart Image Resizer', 'smart-image-resizer'); ?></h1>
                    <p><?php esc_html_e('Generate consistent image sizes for your theme without touching originals. Resize new uploads automatically or process existing Media Library images in safe batches.', 'smart-image-resizer'); ?></p>
                </div>
                <div class="sir-stats">
                    <strong><?php echo esc_html(count($presets)); ?></strong>
                    <span><?php esc_html_e('active presets', 'smart-image-resizer'); ?></span>
                </div>
            </div>

            <?php if ($notice === 'settings_saved') : ?>
                <div class="notice notice-success is-dismissible"><p><?php esc_html_e('Settings saved. Future uploads will use your latest presets.', 'smart-image-resizer'); ?></p></div>
            <?php endif; ?>
            <?php if ($notice === 'bulk_done' && is_array($last)) : ?>
                <div class="notice notice-success is-dismissible"><p><?php printf(esc_html__('Bulk job complete: %1$d image(s) resized, %2$d skipped, %3$d error(s).', 'smart-image-resizer'), absint($last['resized']), absint($last['skipped']), absint($last['errors'])); ?></p></div>
            <?php endif; ?>

            <div class="sir-grid">
                <form method="post" class="sir-card sir-card-wide">
                    <?php wp_nonce_field(self::NONCE_ACTION); ?>
                    <input type="hidden" name="sir_action" value="save_settings">
                    <h2><?php esc_html_e('Resize presets', 'smart-image-resizer'); ?></h2>
                    <p class="description"><?php esc_html_e('Set up to six presets. Height can be 0 for proportional resizing. Crop creates exact dimensions.', 'smart-image-resizer'); ?></p>
                    <table class="widefat striped sir-table">
                        <thead><tr><th>Name</th><th>Slug</th><th>Width</th><th>Height</th><th>Crop</th></tr></thead>
                        <tbody>
                        <?php for ($i = 0; $i < 6; $i++) : $preset = $presets[$i] ?? ['name'=>'','slug'=>'','width'=>'','height'=>'','crop'=>0]; ?>
                            <tr>
                                <td><input class="regular-text" name="preset_name[]" value="<?php echo esc_attr($preset['name']); ?>" placeholder="Hero Banner"></td>
                                <td><input name="preset_slug[]" value="<?php echo esc_attr($preset['slug']); ?>" placeholder="hero-banner"></td>
                                <td><input type="number" min="0" name="preset_width[]" value="<?php echo esc_attr($preset['width']); ?>"></td>
                                <td><input type="number" min="0" name="preset_height[]" value="<?php echo esc_attr($preset['height']); ?>"></td>
                                <td><label><input type="checkbox" name="preset_crop[<?php echo esc_attr($i); ?>]" value="1" <?php checked(!empty($preset['crop'])); ?>> Exact crop</label></td>
                            </tr>
                        <?php endfor; ?>
                        </tbody>
                    </table>

                    <h2><?php esc_html_e('Automation', 'smart-image-resizer'); ?></h2>
                    <label class="sir-toggle"><input type="checkbox" name="auto_resize" value="1" <?php checked(!empty($settings['auto_resize'])); ?>> <?php esc_html_e('Resize new image uploads automatically', 'smart-image-resizer'); ?></label>
                    <label class="sir-toggle"><input type="checkbox" name="webp" value="1" <?php checked(!empty($settings['webp'])); ?>> <?php esc_html_e('Also attempt WebP copies when the server supports it', 'smart-image-resizer'); ?></label>
                    <p class="sir-safe"><?php esc_html_e('Safety mode is on: originals are kept by default for reversible workflows.', 'smart-image-resizer'); ?></p>
                    <?php submit_button(__('Save settings', 'smart-image-resizer')); ?>
                </form>

                <div class="sir-card">
                    <h2><?php esc_html_e('Bulk resize existing media', 'smart-image-resizer'); ?></h2>
                    <p><?php esc_html_e('Process a small batch of existing images. Re-run batches until your library is complete.', 'smart-image-resizer'); ?></p>
                    <form method="post">
                        <?php wp_nonce_field(self::NONCE_ACTION); ?>
                        <input type="hidden" name="sir_action" value="bulk_resize">
                        <label for="sir-preset"><strong><?php esc_html_e('Preset', 'smart-image-resizer'); ?></strong></label>
                        <select id="sir-preset" name="preset_slug">
                            <?php foreach ($presets as $preset) : ?>
                                <option value="<?php echo esc_attr($preset['slug']); ?>"><?php echo esc_html($preset['name']); ?></option>
                            <?php endforeach; ?>
                        </select>
                        <label for="sir-limit"><strong><?php esc_html_e('Batch size', 'smart-image-resizer'); ?></strong></label>
                        <input id="sir-limit" type="number" name="limit" value="20" min="1" max="50">
                        <?php submit_button(__('Run bulk resize', 'smart-image-resizer'), 'primary', 'submit', false); ?>
                    </form>
                </div>

                <div class="sir-card">
                    <h2><?php esc_html_e('Recent activity', 'smart-image-resizer'); ?></h2>
                    <?php $this->render_logs(); ?>
                </div>
            </div>
        </div>
        <?php
    }

    private function render_logs(): void {
        $logs = get_option(self::LOG_OPTION, []);
        if (!$logs) {
            echo '<p class="description">' . esc_html__('No resize jobs yet. Upload an image or run a bulk job to see activity here.', 'smart-image-resizer') . '</p>';
            return;
        }
        echo '<ul class="sir-log">';
        foreach (array_slice(array_reverse($logs), 0, 8) as $log) {
            printf('<li><strong>%s</strong><span>%s</span></li>', esc_html($log['title'] ?? 'Image'), esc_html($log['message'] ?? 'Resized'));
        }
        echo '</ul>';
    }

    public function resize_on_upload(int $attachment_id): void {
        $settings = $this->get_settings();
        if (empty($settings['auto_resize']) || !wp_attachment_is_image($attachment_id)) {
            return;
        }
        foreach ($settings['presets'] as $preset) {
            $this->resize_attachment($attachment_id, $preset, !empty($settings['webp']));
        }
    }

    public function bulk_resize(string $preset_slug, int $limit): array {
        $settings = $this->get_settings();
        $preset = null;
        foreach ($settings['presets'] as $candidate) {
            if ($candidate['slug'] === $preset_slug) {
                $preset = $candidate;
                break;
            }
        }
        if (!$preset) {
            return ['resized' => 0, 'skipped' => 0, 'errors' => 1];
        }
        $ids = get_posts([
            'post_type' => 'attachment',
            'post_mime_type' => 'image',
            'post_status' => 'inherit',
            'posts_per_page' => $limit,
            'fields' => 'ids',
            'orderby' => 'date',
            'order' => 'DESC',
        ]);
        $result = ['resized' => 0, 'skipped' => 0, 'errors' => 0];
        foreach ($ids as $id) {
            $status = $this->resize_attachment((int) $id, $preset, !empty($settings['webp']));
            if ($status === true) {
                $result['resized']++;
            } elseif ($status === 'exists') {
                $result['skipped']++;
            } else {
                $result['errors']++;
            }
        }
        return $result;
    }

    private function resize_attachment(int $attachment_id, array $preset, bool $make_webp = false) {
        $file = get_attached_file($attachment_id);
        if (!$file || !file_exists($file)) {
            return false;
        }
        $editor = wp_get_image_editor($file);
        if (is_wp_error($editor)) {
            return false;
        }
        $info = pathinfo($file);
        $slug = sanitize_title($preset['slug']);
        $width = absint($preset['width']);
        $height = absint($preset['height']);
        $dest = trailingslashit($info['dirname']) . $info['filename'] . '-' . $slug . '-' . $width . 'x' . ($height ?: 'auto') . '.' . strtolower($info['extension']);
        $existing = get_post_meta($attachment_id, self::META_KEY, true);
        $existing = is_array($existing) ? $existing : [];
        if (file_exists($dest)) {
            return 'exists';
        }
        $resized = $editor->resize($width, $height ?: null, !empty($preset['crop']));
        if (is_wp_error($resized)) {
            return false;
        }
        $saved = $editor->save($dest);
        if (is_wp_error($saved) || empty($saved['path'])) {
            return false;
        }
        $existing[$slug] = [
            'path' => $saved['path'],
            'file' => wp_basename($saved['path']),
            'width' => $saved['width'] ?? $width,
            'height' => $saved['height'] ?? $height,
            'created' => current_time('mysql'),
        ];
        if ($make_webp && function_exists('imagewebp')) {
            $webp_editor = wp_get_image_editor($saved['path']);
            if (!is_wp_error($webp_editor)) {
                $webp_dest = preg_replace('/\.[^.]+$/', '.webp', $saved['path']);
                $webp_saved = $webp_editor->save($webp_dest, 'image/webp');
                if (!is_wp_error($webp_saved) && !empty($webp_saved['path'])) {
                    $existing[$slug]['webp'] = wp_basename($webp_saved['path']);
                }
            }
        }
        update_post_meta($attachment_id, self::META_KEY, $existing);
        $this->add_log(get_the_title($attachment_id), sprintf('Created %s at %sx%s', $preset['name'], $existing[$slug]['width'], $existing[$slug]['height']));
        return true;
    }

    private function add_log(string $title, string $message): void {
        $logs = get_option(self::LOG_OPTION, []);
        $logs[] = ['time' => current_time('mysql'), 'title' => $title ?: 'Untitled image', 'message' => $message];
        update_option(self::LOG_OPTION, array_slice($logs, -30));
    }
}

Smart_Image_Resizer::instance();
