<?php
// File: modules/homepage-image-alt-audit-api.php
// Endpoint: GET /wp-json/myaio/v1/homepage-image-alt-audit
//
// Params:
//   ?url=https://example.com/          (default: home_url('/'))
//   ?include_raw_images=1             (include all <img> before filtering)
//   ?include_removed=1                (include removed images with reasons)
//   ?key=YOUR_KEY                     (auth via shared plugin key validator)

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

// ✅ Shared auth (same approach across modules)
require_once plugin_dir_path(__FILE__) . '../includes/sac-utils.php';

add_action('rest_api_init', function () {
    register_rest_route('myaio/v1', '/homepage-image-alt-audit', [
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'myaio_imgalt_api',
        'permission_callback' => 'myaio_sac_permission_check', // ✅ unified auth
        'args' => [
            'url' => ['required' => false, 'type' => 'string'],
            'include_raw_images' => ['required' => false],
            'include_removed' => ['required' => false],
            'key' => ['required' => false, 'type' => 'string'],
        ],
    ]);
});

/* =============================================================================
 * PARAMS
 * ============================================================================= */

if (!function_exists('myaio_imgalt_bool')) {
    function myaio_imgalt_bool($v) {
        if (is_bool($v)) return $v;
        $v = strtolower(trim((string)$v));
        return in_array($v, ['1', 'true', 'yes', 'on'], true);
    }
}

/* =============================================================================
 * MAIN
 * ============================================================================= */

if (!function_exists('myaio_imgalt_api')) {
    function myaio_imgalt_api(WP_REST_Request $request) {
        $include_raw_images = myaio_imgalt_bool($request->get_param('include_raw_images'));
        $include_removed    = myaio_imgalt_bool($request->get_param('include_removed'));

        $url = trim((string)$request->get_param('url'));
        if ($url === '') $url = home_url('/');

        if (!preg_match('#^https?://#i', $url)) {
            return new WP_REST_Response([
                'ok' => false,
                'message' => 'Invalid url. Use absolute http(s) URL.',
                'url' => $url,
            ], 200);
        }

        if (!class_exists('DOMDocument')) {
            return new WP_REST_Response([
                'ok' => false,
                'message' => 'PHP DOM extension is missing on this server (DOMDocument not available).',
            ], 200);
        }

        $resp = wp_remote_get($url, [
            'timeout'     => 20,
            'redirection' => 5,
            'headers'     => [
                'User-Agent' => 'Mozilla/5.0 (HomepageImageAltAuditBot)',
                'Accept'     => 'text/html',
            ],
        ]);

        if (is_wp_error($resp)) {
            return new WP_REST_Response([
                'ok' => false,
                'url' => $url,
                'message' => 'Could not fetch the page.',
                'error' => $resp->get_error_message(),
            ], 200);
        }

        $html = wp_remote_retrieve_body($resp);
        if (!$html) {
            return new WP_REST_Response([
                'ok' => false,
                'url' => $url,
                'message' => 'Page HTML was empty.',
            ], 200);
        }

        $dom = myaio_imgalt_dom_from_html($html);
        if (!$dom) {
            return new WP_REST_Response([
                'ok' => false,
                'url' => $url,
                'message' => 'Could not parse HTML.',
            ], 200);
        }

        $xpath = new DOMXPath($dom);
        myaio_imgalt_remove_noise($xpath, $dom->documentElement);

        $raw_images = myaio_imgalt_extract_images($xpath, $dom, $url);

        // If no <img> elements exist at all
        if (empty($raw_images)) {
            return new WP_REST_Response([
                'ok' => true,
                'url' => $url,
                'status' => 'NO_IMAGES',
                'counts' => [
                    'total_found' => 0,
                    'decorative_removed' => 0,
                    'small_removed' => 0,
                    'eligible_total' => 0,
                    'with_alt' => 0,
                    'without_alt' => 0,
                ],
                'images' => [
                    'eligible' => [],
                    'with_alt' => [],
                    'without_alt' => [],
                ],
            ], 200);
        }

        // Step 1: decorative removal
        $decorative_removed = [];
        $step1 = [];

        foreach ($raw_images as $img) {
            $decor = myaio_imgalt_is_decorative($img);
            if ($decor['is_decorative']) {
                $img['removed'] = true;
                $img['removed_stage'] = 'decorative';
                $img['removed_reasons'] = $decor['reasons'];
                $decorative_removed[] = $img;
            } else {
                $step1[] = $img;
            }
        }

        // Step 2: size filter >= 100x100 (unknown dims => keep)
        $small_removed = [];
        $eligible = [];

        foreach ($step1 as $img) {
            $decision = myaio_imgalt_size_decision($img, 100, 100);
            $img['size_check'] = $decision;

            if ($decision['keep']) {
                $eligible[] = $img;
            } else {
                $img['removed'] = true;
                $img['removed_stage'] = 'size';
                $img['removed_reasons'] = [$decision['reason']];
                $small_removed[] = $img;
            }
        }

        // ALT evaluation on eligible images only
        $with_alt = [];
        $without_alt = [];

        foreach ($eligible as $img) {
            if (myaio_imgalt_has_alt($img['alt'] ?? '')) $with_alt[] = $img;
            else $without_alt[] = $img;
        }

        $out = [
            'ok' => true,
            'url' => $url,
            'status' => 'OK',
            'counts' => [
                'total_found' => count($raw_images),
                'decorative_removed' => count($decorative_removed),
                'small_removed' => count($small_removed),
                'eligible_total' => count($eligible),
                'with_alt' => count($with_alt),
                'without_alt' => count($without_alt),
            ],
            'images' => [
                'eligible' => $eligible,
                'with_alt' => $with_alt,
                'without_alt' => $without_alt,
            ],
        ];

        if ($include_raw_images) {
            $out['images']['raw'] = $raw_images;
        }

        if ($include_removed) {
            $out['images']['removed'] = array_merge($decorative_removed, $small_removed);
        }

        return new WP_REST_Response($out, 200);
    }
}

/* =============================================================================
 * EXTRACTION
 * ============================================================================= */

if (!function_exists('myaio_imgalt_extract_images')) {
    function myaio_imgalt_extract_images(DOMXPath $xpath, DOMDocument $dom, $page_url) {
        $out = [];
        $nodes = $xpath->query("//img");
        if (!$nodes || !$nodes->length) return $out;

        foreach ($nodes as $img) {
            /** @var DOMElement $img */
            $src   = trim((string)$img->getAttribute('src'));
            $alt   = (string)$img->getAttribute('alt');
            $w     = trim((string)$img->getAttribute('width'));
            $h     = trim((string)$img->getAttribute('height'));
            $class = trim((string)$img->getAttribute('class'));
            $id    = trim((string)$img->getAttribute('id'));

            $srcset_raw  = trim((string)$img->getAttribute('srcset'));
            $srcset_best = $srcset_raw ? myaio_imgalt_pick_best_srcset($srcset_raw) : null;
            if ($src === '' && $srcset_best) $src = $srcset_best;

            $abs = myaio_imgalt_resolve_url($src, $page_url);

            $width  = is_numeric($w) ? (int)$w : null;
            $height = is_numeric($h) ? (int)$h : null;

            $inferred = (!$width || !$height) ? myaio_imgalt_infer_dims($abs ?: $src) : null;
            if (!$width && $inferred) $width = $inferred['width'];
            if (!$height && $inferred) $height = $inferred['height'];

            $out[] = [
                'src' => $src ?: null,
                'src_abs' => $abs,
                'srcset_raw' => $srcset_raw ?: null,
                'srcset_best' => $srcset_best ?: null,
                'alt' => $alt,
                'alt_trimmed' => trim($alt),
                'width' => $width,
                'height' => $height,
                'class' => $class ?: null,
                'id' => $id ?: null,
            ];
        }

        return $out;
    }
}

if (!function_exists('myaio_imgalt_pick_best_srcset')) {
    function myaio_imgalt_pick_best_srcset($srcset) {
        $parts = array_map('trim', explode(',', (string)$srcset));
        $best = null;
        $best_w = -1;

        foreach ($parts as $p) {
            if ($p === '') continue;
            $bits = preg_split('/\s+/', trim($p));
            $url = $bits[0] ?? '';
            $desc = $bits[1] ?? '';
            $w = null;

            if (preg_match('/^(\d+)w$/i', $desc, $m)) $w = (int)$m[1];

            if ($w !== null) {
                if ($w > $best_w) { $best_w = $w; $best = $url; }
            } elseif ($best === null) {
                $best = $url;
            }
        }

        return $best ? trim($best) : null;
    }
}

/* =============================================================================
 * FILTERS
 * ============================================================================= */

if (!function_exists('myaio_imgalt_is_decorative')) {
    function myaio_imgalt_is_decorative(array $img) {
        $reasons = [];
        $src = strtolower((string)($img['src_abs'] ?: $img['src'] ?: ''));
        $class = strtolower((string)($img['class'] ?: ''));
        $id = strtolower((string)($img['id'] ?: ''));

        if ($src === '') $reasons[] = 'missing_src';

        if (preg_match('/\.(svg|ico)(\?.*)?$/i', $src)) $reasons[] = 'svg_or_ico';

        foreach (['icon','icons','favicon','sprite','logo','logos'] as $kw) {
            if (strpos($src, $kw) !== false) $reasons[] = "keyword:$kw";
            if (strpos($class, $kw) !== false) $reasons[] = "class_keyword:$kw";
            if (strpos($id, $kw) !== false) $reasons[] = "id_keyword:$kw";
        }

        if (preg_match('/\.(gif)(\?.*)?$/i', $src)) $reasons[] = 'gif_possible_ui';

        return [
            'is_decorative' => !empty($reasons),
            'reasons' => $reasons,
        ];
    }
}

if (!function_exists('myaio_imgalt_size_decision')) {
    function myaio_imgalt_size_decision(array $img, $min_w, $min_h) {
        $w = isset($img['width']) ? (int)$img['width'] : 0;
        $h = isset($img['height']) ? (int)$img['height'] : 0;

        if ($w <= 0 || $h <= 0) {
            return [
                'keep' => true,
                'known' => false,
                'width' => $w ?: null,
                'height' => $h ?: null,
                'reason' => 'unknown_dimensions_kept',
            ];
        }

        if ($w >= $min_w && $h >= $min_h) {
            return [
                'keep' => true,
                'known' => true,
                'width' => $w,
                'height' => $h,
                'reason' => 'meets_min_size',
            ];
        }

        return [
            'keep' => false,
            'known' => true,
            'width' => $w,
            'height' => $h,
            'reason' => "below_min_size_{$min_w}x{$min_h}",
        ];
    }
}

if (!function_exists('myaio_imgalt_has_alt')) {
    function myaio_imgalt_has_alt($alt) {
        return trim((string)$alt) !== '';
    }
}

/* =============================================================================
 * URL + DIM HELPERS
 * ============================================================================= */

if (!function_exists('myaio_imgalt_resolve_url')) {
    function myaio_imgalt_resolve_url($maybe_relative, $base_url) {
        $u = trim((string)$maybe_relative);
        if ($u === '') return null;

        if (preg_match('#^https?://#i', $u)) return $u;
        if (strpos($u, '//') === 0) {
            $scheme = (stripos($base_url, 'https://') === 0) ? 'https:' : 'http:';
            return $scheme . $u;
        }
        if (stripos($u, 'data:') === 0) return $u;

        $p = wp_parse_url($base_url);
        if (!$p || empty($p['host'])) return $u;

        $scheme = $p['scheme'] ?? 'https';
        $host = $p['host'];
        $port = isset($p['port']) ? (':' . $p['port']) : '';

        if (strpos($u, '/') === 0) {
            return $scheme . '://' . $host . $port . $u;
        }

        $base_path = $p['path'] ?? '/';
        $dir = preg_replace('#/[^/]*$#', '/', $base_path);
        return $scheme . '://' . $host . $port . $dir . $u;
    }
}

if (!function_exists('myaio_imgalt_infer_dims')) {
    function myaio_imgalt_infer_dims($url) {
        $u = (string)$url;
        if (preg_match('/[-_](\d{2,5})x(\d{2,5})(?=\D|$)/', $u, $m)) {
            return ['width' => (int)$m[1], 'height' => (int)$m[2]];
        }
        return null;
    }
}

/* =============================================================================
 * DOM UTILS
 * ============================================================================= */

if (!function_exists('myaio_imgalt_dom_from_html')) {
    function myaio_imgalt_dom_from_html($html) {
        libxml_use_internal_errors(true);
        $dom = new DOMDocument();
        $ok = @$dom->loadHTML('<?xml encoding="utf-8" ?>' . (string)$html);
        libxml_clear_errors();
        return $ok ? $dom : null;
    }
}

if (!function_exists('myaio_imgalt_remove_noise')) {
    function myaio_imgalt_remove_noise(DOMXPath $xpath, DOMNode $context) {
        foreach (['.//script', './/style', './/noscript'] as $q) {
            $nodes = $xpath->query($q, $context);
            if (!$nodes) continue;
            for ($i = $nodes->length - 1; $i >= 0; $i--) {
                $n = $nodes->item($i);
                if ($n && $n->parentNode) $n->parentNode->removeChild($n);
            }
        }
    }
}
