<?php
defined( 'ABSPATH' ) || exit;

class SITECL_Alt_Scanner {

    public static function scan(): array {
        $missing = array_merge(
            self::scan_media_library(),
            self::scan_post_content()
        );

        if ( empty( $missing ) ) {
            return [];
        }

        $issues = [];
        foreach ( $missing as $item ) {
            $issues[] = [
                'type'     => 'alt_tags',
                'severity' => $item['seo_impact'] === 'high' ? 'warning' : 'info',
                'title'    => sprintf(
                    /* translators: %s: image filename or URL */
                    __( 'Missing alt text: %s', 'site-cliniq' ),
                    esc_html( $item['filename'] ?? $item['src'] ?? '' )
                ),
                'detail'   => sprintf(
                    /* translators: %1$s: SEO impact level (HIGH/MEDIUM/LOW), %2$s: post or page title where image is used */
                    __( 'SEO impact: %1$s. Used in: %2$s.', 'site-cliniq' ),
                    strtoupper( $item['seo_impact'] ),
                    esc_html( $item['context'] ?? 'unknown' )
                ),
                'item'     => $item,
            ];
        }

        return $issues;
    }

    /**
     * Return full audit data (used by the alt-tags admin view).
     */
    public static function get_full_audit(): array {
        return [
            'library' => self::scan_media_library(),
            'content' => self::scan_post_content(),
        ];
    }

    /**
     * Save alt text for a media library item.
     */
    public static function save_alt_text( int $attachment_id, string $alt_text ): bool {
        if ( ! current_user_can( 'edit_post', $attachment_id ) ) {
            return false;
        }
        update_post_meta(
            $attachment_id,
            '_wp_attachment_image_alt',
            sanitize_text_field( $alt_text )
        );
        return true;
    }

    // -------------------------------------------------------------------------

    private static function scan_media_library(): array {
        $attachments = get_posts( [
            'post_type'      => 'attachment',
            'post_mime_type' => 'image',
            'post_status'    => 'inherit',
            'posts_per_page' => 500,
            'fields'         => 'ids',
        ] );

        $missing = [];

        foreach ( $attachments as $id ) {
            $alt = get_post_meta( $id, '_wp_attachment_image_alt', true );
            if ( ! empty( trim( (string) $alt ) ) ) {
                continue;
            }

            $post     = get_post( $id );
            $filename = basename( get_attached_file( $id ) ?? '' );
            $title    = ! empty( $post->post_title ) ? $post->post_title : '';
            $caption  = ! empty( $post->post_excerpt ) ? $post->post_excerpt : '';

            // Find the parent post title if image is attached to a post.
            $parent_title = '';
            if ( ! empty( $post->post_parent ) ) {
                $parent = get_post( $post->post_parent );
                if ( $parent ) {
                    $parent_title = $parent->post_title;
                }
            }

            $missing[] = [
                'source'       => 'library',
                'id'           => $id,
                'filename'     => $filename,
                'title'        => $title,
                'caption'      => $caption,
                'parent_title' => $parent_title,
                'edit_url'     => get_edit_post_link( $id, 'raw' ),
                'seo_impact'   => self::score_seo_impact( $id ),
                'context'      => $parent_title ?: 'Media Library',
                'suggestions'  => self::build_suggestions( $filename, $title, $caption, $parent_title ),
            ];
        }

        return $missing;
    }

    private static function scan_post_content(): array {
        $posts = get_posts( [
            'post_type'      => [ 'post', 'page' ],
            'post_status'    => 'publish',
            'posts_per_page' => 200,
        ] );

        $missing = [];

        foreach ( $posts as $post ) {
            preg_match_all( '/<img[^>]+>/i', $post->post_content, $img_tags );

            foreach ( $img_tags[0] as $tag ) {
                // Skip if alt attribute exists and is non-empty.
                if ( preg_match( '/alt=["\']([^"\']*)["\']/', $tag, $alt_match ) && ! empty( trim( $alt_match[1] ) ) ) {
                    continue;
                }

                preg_match( '/src=["\']([^"\']+)["\']/', $tag, $src_match );
                $src = $src_match[1] ?? '';

                $missing[] = [
                    'source'     => 'content',
                    'post_id'    => $post->ID,
                    'post_title' => $post->post_title,
                    'src'        => $src,
                    'edit_url'   => get_edit_post_link( $post->ID, 'raw' ),
                    'seo_impact' => self::score_content_seo_impact( $post ),
                    'context'    => esc_html( $post->post_title ),
                ];
            }
        }

        return $missing;
    }

    /**
     * Build multiple distinct alt text suggestions from all available image metadata.
     *
     * @return array<array{ label: string, value: string }>
     */
    private static function build_suggestions( string $filename, string $title, string $caption, string $parent_title ): array {
        $suggestions = [];
        $seen        = [];

        $name_without_ext = pathinfo( $filename, PATHINFO_FILENAME );
        $cleaned_filename = ucwords( trim( preg_replace( '/[\s_-]+/', ' ', $name_without_ext ) ) );
        $site_name        = get_bloginfo( 'name' );

        // Detect UUID / hash filenames — not useful as alt text.
        $is_uuid_filename = (bool) preg_match( '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i', $name_without_ext )
                         || (bool) preg_match( '/^[a-f0-9]{20,}$/i', $name_without_ext );

        // WP auto-sets title = filename slug, so treat them as the same.
        $title_is_filename = strtolower( $title ) === strtolower( $cleaned_filename )
                          || strtolower( $title ) === strtolower( $name_without_ext );

        // Meaningful image title = exists, not blank, not same as filename, not a UUID.
        $meaningful_title = ! empty( $title ) && ! $title_is_filename && ! $is_uuid_filename;

        $add = static function ( string $label, string $value ) use ( &$suggestions, &$seen ): void {
            $value = wp_strip_all_tags( trim( $value ) );
            if ( empty( $value ) || isset( $seen[ strtolower( $value ) ] ) ) {
                return;
            }
            $seen[ strtolower( $value ) ] = true;
            $suggestions[] = [ 'label' => $label, 'value' => $value ];
        };

        // 1. Caption — human-written, best quality.
        if ( ! empty( $caption ) ) {
            $add( __( 'Caption', 'site-cliniq' ), $caption );
        }

        // 2. Site Title alone.
        if ( ! empty( $site_name ) ) {
            $add( __( 'Site Title', 'site-cliniq' ), $site_name );
        }

        // 3. Image Title (only when meaningfully different from filename).
        if ( $meaningful_title ) {
            $add( __( 'Image Title', 'site-cliniq' ), $title );
        }

        // 4. Site Title + Image Title.
        if ( ! empty( $site_name ) && $meaningful_title ) {
            $add(
                __( 'Site + Image Title', 'site-cliniq' ),
                /* translators: 1: site name, 2: image title */
                sprintf( _x( '%1$s — %2$s', 'alt text: site name + image title', 'site-cliniq' ), $site_name, $title )
            );
        }

        // 5. Post/page title where the image is used.
        if ( ! empty( $parent_title ) ) {
            $add( __( 'Post Title', 'site-cliniq' ), $parent_title );
        }

        // 6. Site Title + Post Title.
        if ( ! empty( $site_name ) && ! empty( $parent_title ) ) {
            $add(
                __( 'Site + Post Title', 'site-cliniq' ),
                /* translators: 1: site name, 2: post title */
                sprintf( _x( '%1$s — %2$s', 'alt text: site name + post title', 'site-cliniq' ), $site_name, $parent_title )
            );
        }

        // 7. Filename — only when it's not a UUID/hash.
        if ( ! $is_uuid_filename ) {
            $add( __( 'Filename', 'site-cliniq' ), $cleaned_filename );

            // Filename + Site.
            if ( ! empty( $site_name ) ) {
                $add(
                    __( 'Filename + Site', 'site-cliniq' ),
                    /* translators: 1: cleaned filename, 2: site name */
                    sprintf( _x( '%1$s — %2$s', 'alt text: filename + site name', 'site-cliniq' ), $cleaned_filename, $site_name )
                );
            }
        }

        return $suggestions;
    }

    private static function score_seo_impact( int $attachment_id ): string {
        // High: used on homepage or landing pages. Medium: inner pages. Low: archives.
        // Direct SQL avoids meta_query (slow query warning) — table name is safe, value is intval.
        global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $used_in = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT post_id FROM {$wpdb->postmeta}
                  WHERE meta_key = '_thumbnail_id'
                    AND meta_value = %d
                  LIMIT 5",
                $attachment_id
            )
        );

        if ( ! empty( $used_in ) ) {
            // Check if used on front page before falling back to medium.
            $front_page_id = (int) get_option( 'page_on_front' );
            if ( $front_page_id && in_array( $front_page_id, $used_in, true ) ) {
                return 'high';
            }

            return 'medium';
        }

        return 'low';
    }

    private static function score_content_seo_impact( WP_Post $post ): string {
        $front_page_id = (int) get_option( 'page_on_front' );

        if ( $post->ID === $front_page_id ) {
            return 'high';
        }

        if ( $post->post_type === 'page' ) {
            return 'medium';
        }

        return 'low';
    }
}
