<?php

/**
 * JCOGS Image Pro - Cache Log JPEG Suffix Normalization Migration
 * ===============================================================
 * Normalizes legacy .jpeg/.jpe cache-log suffixes to .jpg for lookup consistency.
 *
 * @category   ExpressionEngine Add-on
 * @package    JCOGS Image Pro
 * @author     JCOGS Design <contact@jcogs.net>
 * @copyright  Copyright (c) 2021 - 2026 JCOGS Design
 * @license    https://jcogs.net/add-ons/license/jcogs_img_pro
 * @version    2.0.6
 * @link       https://jcogs.net/
 * @since      2.0.5
 */

use ExpressionEngine\Service\Migration\Migration;

class NormalizeCacheLogJpegSuffixes extends Migration
{
    private const TABLE = 'jcogs_img_pro_cache_log';
    private const SETTINGS_TABLE = 'jcogs_img_pro_settings';
    private const SETTING_MAX_SOURCE_FILENAME_LENGTH = 'img_cp_default_max_source_filename_length';
    private const SETTING_MIN_PHP_RAM = 'img_cp_default_min_php_ram';

    public function up()
    {
        if (ee()->db->table_exists(self::TABLE)) {
            $this->normalizeCacheLogJpegSuffixes();
        }

        $this->normalizeLegacySettings();
    }

    public function down()
    {
        // Irreversible data normalization migration.
    }

    private function normalizeCacheLogJpegSuffixes(): void
    {
        $table = ee()->db->dbprefix . self::TABLE;

        $query = ee()->db->query(
            "SELECT id, site_id, adapter_name, adapter_type, path, image_name\n"
            . "FROM `{$table}`\n"
            . "WHERE LOWER(path) LIKE '%.jpeg' OR LOWER(path) LIKE '%.jpe'\n"
            . "   OR LOWER(image_name) LIKE '%.jpeg' OR LOWER(image_name) LIKE '%.jpe'"
        );

        foreach ($query->result_array() as $row) {
            $id = (int) ($row['id'] ?? 0);
            if ($id <= 0) {
                continue;
            }

            $newPath = $this->normalizeJpegSuffix((string) ($row['path'] ?? ''));
            $newImageName = $this->normalizeJpegSuffix((string) ($row['image_name'] ?? ''));

            if ($newPath === ($row['path'] ?? '') && $newImageName === ($row['image_name'] ?? '')) {
                continue;
            }

            $duplicateId = ee()->db->select('id')
                ->from(self::TABLE)
                ->where('site_id', (int) $row['site_id'])
                ->where('adapter_name', (string) $row['adapter_name'])
                ->where('adapter_type', (string) $row['adapter_type'])
                ->where('path', $newPath)
                ->where('image_name', $newImageName)
                ->where('id !=', $id)
                ->limit(1)
                ->get()
                ->row('id');

            if ($duplicateId) {
                ee()->db->where('id', $id)->delete(self::TABLE);
                continue;
            }

            ee()->db->where('id', $id)->update(self::TABLE, [
                'path' => $newPath,
                'image_name' => $newImageName,
            ]);
        }
    }

    private function normalizeLegacySettings(): void
    {
        if (!ee()->db->table_exists(self::SETTINGS_TABLE)) {
            return;
        }

        $settings = ee()->db->select('site_id, setting_name, value')
            ->from(self::SETTINGS_TABLE)
            ->where_in('setting_name', [
                self::SETTING_MAX_SOURCE_FILENAME_LENGTH,
                self::SETTING_MIN_PHP_RAM,
            ])
            ->get()
            ->result_array();

        foreach ($settings as $setting) {
            $siteId = (int) ($setting['site_id'] ?? 0);
            $settingName = (string) ($setting['setting_name'] ?? '');
            $currentValue = trim((string) ($setting['value'] ?? ''));

            if ($siteId <= 0 || $settingName === '') {
                continue;
            }

            if ($settingName === self::SETTING_MAX_SOURCE_FILENAME_LENGTH) {
                $currentLength = (int) $currentValue;
                if ($currentLength > 175) {
                    ee()->db->where('site_id', $siteId)
                        ->where('setting_name', self::SETTING_MAX_SOURCE_FILENAME_LENGTH)
                        ->update(self::SETTINGS_TABLE, ['value' => '175']);
                }
                continue;
            }

            if ($settingName === self::SETTING_MIN_PHP_RAM) {
                $currentRamMb = $this->normalizeMemoryToMegabytes($currentValue);
                if ($currentRamMb === 64) {
                    ee()->db->where('site_id', $siteId)
                        ->where('setting_name', self::SETTING_MIN_PHP_RAM)
                        ->update(self::SETTINGS_TABLE, ['value' => '256']);
                }
            }
        }
    }

    private function normalizeJpegSuffix(string $value): string
    {
        return preg_replace('/\.jpe?g$/i', '.jpg', $value) ?? $value;
    }

    private function normalizeMemoryToMegabytes(string $value): ?int
    {
        $trimmed = trim($value);
        if ($trimmed === '') {
            return null;
        }

        if (!preg_match('/^(\d+(?:\.\d+)?)\s*([kmgt]?b?)?$/i', $trimmed, $matches)) {
            return null;
        }

        $number = (float) ($matches[1] ?? 0);
        $unit = strtoupper((string) ($matches[2] ?? 'M'));

        if ($unit === '' || $unit === 'B' || $unit === 'MB') {
            return (int) round($number);
        }

        if ($unit === 'K' || $unit === 'KB') {
            return (int) round($number / 1024);
        }

        if ($unit === 'M') {
            return (int) round($number);
        }

        if ($unit === 'G' || $unit === 'GB') {
            return (int) round($number * 1024);
        }

        if ($unit === 'T' || $unit === 'TB') {
            return (int) round($number * 1024 * 1024);
        }

        return null;
    }
}
