<?php
declare(strict_types=1);

namespace ProRank\SEO\Core\Diagnostics;

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

/**
 * Detects multiple Google tag emitters without changing frontend output.
 */
final class GoogleTagConflictDetector {

    /**
     * @return array{has_conflict: bool, sources: array<int, array<string, mixed>>, recommendation: string}
     */
    public function detect(): array {
        $sources = array_merge(
            $this->detect_site_kit_sources(),
            $this->detect_prorank_ga4_source(),
            $this->detect_header_injection_sources()
        );

        /**
         * Allows integrations to report Google tag sources they know they emit.
         *
         * Expected item shape:
         * [
         *   'key' => 'unique-source-key',
         *   'type' => 'gtm|gtag|ads',
         *   'label' => 'Human label',
         *   'ids' => ['GTM-...', 'G-...', 'AW-...'],
         *   'details' => 'Optional detail',
         * ]
         */
        $sources = apply_filters( 'prorank_google_tag_conflict_sources', $sources );
        $sources = $this->normalize_sources( is_array( $sources ) ? $sources : [] );

        return [
            'has_conflict'   => $this->has_conflict( $sources ),
            'sources'        => array_values( $sources ),
            'recommendation' => 'Choose one source of truth for Google tags: either Google Tag Manager or direct Google tags/Ads snippets. ProRank only reports this; it does not remove tracking code automatically.',
        ];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function detect_site_kit_sources(): array {
        $sources = [];

        $analytics = $this->get_option_array( 'googlesitekit_analytics-4_settings' );
        if ( $this->is_enabled_snippet( $analytics ) ) {
            $ids = $this->extract_ids_from_values( [
                $analytics['googleTagID'] ?? '',
                $analytics['measurementID'] ?? '',
                $analytics['propertyID'] ?? '',
                $analytics['googleTagContainerDestinationIDs'] ?? [],
            ] );

            if ( ! empty( $ids ) ) {
                $sources[] = [
                    'key'     => 'sitekit_analytics',
                    'type'    => 'gtag',
                    'label'   => 'Site Kit Analytics / Google tag',
                    'ids'     => $ids,
                    'details' => 'Site Kit is configured to print the Analytics Google tag snippet.',
                ];
            }
        }

        $tagmanager = $this->get_option_array( 'googlesitekit_tagmanager_settings' );
        if ( $this->is_enabled_snippet( $tagmanager ) ) {
            $ids = $this->extract_ids_from_values( [
                $tagmanager['containerID'] ?? '',
                $tagmanager['ampContainerID'] ?? '',
            ] );

            if ( ! empty( $ids ) ) {
                $sources[] = [
                    'key'     => 'sitekit_tagmanager',
                    'type'    => 'gtm',
                    'label'   => 'Site Kit Tag Manager',
                    'ids'     => $ids,
                    'details' => 'Site Kit is configured to print a Google Tag Manager container.',
                ];
            }
        }

        $ads                 = $this->get_option_array( 'googlesitekit_ads_settings' );
        $conversion_tracking = $this->get_option_array( 'googlesitekit_conversion_tracking' );
        $ads_ids             = $this->extract_ids_from_values( [
            $ads['conversionID'] ?? '',
            $ads['googleTagID'] ?? '',
        ] );

        if ( ! empty( $ads_ids ) || $this->is_truthy( $conversion_tracking['enabled'] ?? false ) ) {
            $sources[] = [
                'key'     => 'sitekit_ads',
                'type'    => 'ads',
                'label'   => 'Site Kit Ads / conversion tracking',
                'ids'     => $ads_ids,
                'details' => 'Site Kit Ads or conversion tracking is active.',
            ];
        }

        return $sources;
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function detect_prorank_ga4_source(): array {
        $settings = $this->get_option_array( 'prorank_settings' );

        if ( ! $this->is_truthy( $settings['ga4_enabled'] ?? false ) ) {
            return [];
        }

        $ids = $this->extract_ids_from_values( [
            $settings['ga4_measurement_id'] ?? '',
            $settings['ga4_google_tag_id'] ?? '',
        ] );

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

        return [
            [
                'key'     => 'prorank_ga4',
                'type'    => 'gtag',
                'label'   => 'ProRank Google Analytics 4',
                'ids'     => $ids,
                'details' => 'The ProRank GA4 module is configured to print a direct Google tag.',
            ],
        ];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function detect_header_injection_sources(): array {
        $option_labels = [
            'ihaf_insert_header'              => 'Insert Headers and Footers header',
            'ihaf_insert_body'                => 'Insert Headers and Footers body',
            'ihaf_insert_footer'              => 'Insert Headers and Footers footer',
            'wpcode_global_header'            => 'WPCode global header',
            'wpcode_global_body'              => 'WPCode global body',
            'wpcode_global_footer'            => 'WPCode global footer',
            'insert_headers_and_footers_code' => 'Header/footer injection snippet',
        ];

        $sources = [];
        foreach ( $option_labels as $option_name => $label ) {
            $snippet = get_option( $option_name, '' );
            if ( is_array( $snippet ) ) {
                $snippet = wp_json_encode( $snippet );
            }

            $snippet = (string) $snippet;
            if ( $snippet === '' || ! $this->contains_google_tag_snippet( $snippet ) ) {
                continue;
            }

            $ids       = $this->extract_ids_from_string( $snippet );
            $is_gtm    = stripos( $snippet, 'googletagmanager.com/gtm.js' ) !== false || $this->contains_id_prefix( $ids, 'GTM-' );
            $sources[] = [
                'key'     => 'snippet_' . $option_name,
                'type'    => $is_gtm ? 'gtm' : 'gtag',
                'label'   => $label,
                'ids'     => $ids,
                'details' => 'A header/body/footer injection option contains Google tag code.',
            ];
        }

        return $sources;
    }

    /**
     * @param array<int, array<string, mixed>> $sources
     * @return array<string, array<string, mixed>>
     */
    private function normalize_sources( array $sources ): array {
        $normalized = [];

        foreach ( $sources as $source ) {
            if ( ! is_array( $source ) ) {
                continue;
            }

            $key   = sanitize_key( (string) ( $source['key'] ?? '' ) );
            $type  = sanitize_key( (string) ( $source['type'] ?? '' ) );
            $label = trim( (string) ( $source['label'] ?? '' ) );

            if ( $key === '' || $label === '' || ! in_array( $type, [ 'gtm', 'gtag', 'ads' ], true ) ) {
                continue;
            }

            $ids = $this->extract_ids_from_values( $source['ids'] ?? [] );

            $normalized[ $key ] = [
                'key'     => $key,
                'type'    => $type,
                'label'   => $label,
                'ids'     => $ids,
                'details' => trim( (string) ( $source['details'] ?? '' ) ),
            ];
        }

        return $normalized;
    }

    /**
     * @param array<string, array<string, mixed>> $sources
     */
    private function has_conflict( array $sources ): bool {
        if ( count( $sources ) < 2 ) {
            return false;
        }

        $has_gtm       = false;
        $has_direct    = false;
        $has_ads       = false;
        $direct_count  = 0;

        foreach ( $sources as $source ) {
            $type = (string) ( $source['type'] ?? '' );

            if ( $type === 'gtm' ) {
                $has_gtm = true;
                continue;
            }

            if ( $type === 'gtag' ) {
                $has_direct = true;
                $direct_count++;
                continue;
            }

            if ( $type === 'ads' ) {
                $has_ads = true;
            }
        }

        if ( $has_gtm && ( $has_direct || $has_ads ) ) {
            return true;
        }

        return $direct_count > 1;
    }

    /**
     * @return array<string, mixed>
     */
    private function get_option_array( string $option_name ): array {
        $value = get_option( $option_name, [] );

        if ( is_array( $value ) ) {
            return $value;
        }

        if ( is_string( $value ) && $value !== '' ) {
            $decoded = json_decode( $value, true );
            if ( is_array( $decoded ) ) {
                return $decoded;
            }
        }

        return [];
    }

    /**
     * @param mixed $settings
     */
    private function is_enabled_snippet( $settings ): bool {
        if ( ! is_array( $settings ) ) {
            return false;
        }

        return $this->is_truthy( $settings['useSnippet'] ?? false );
    }

    /**
     * @param mixed $value
     */
    private function is_truthy( $value ): bool {
        if ( is_bool( $value ) ) {
            return $value;
        }

        if ( is_numeric( $value ) ) {
            return (int) $value === 1;
        }

        if ( is_string( $value ) ) {
            return in_array( strtolower( trim( $value ) ), [ '1', 'true', 'yes', 'on', 'enabled' ], true );
        }

        return false;
    }

    /**
     * @param mixed $values
     * @return array<int, string>
     */
    private function extract_ids_from_values( $values ): array {
        if ( ! is_array( $values ) ) {
            $values = [ $values ];
        }

        $ids = [];
        foreach ( $values as $value ) {
            if ( is_array( $value ) ) {
                $ids = array_merge( $ids, $this->extract_ids_from_values( $value ) );
                continue;
            }

            $ids = array_merge( $ids, $this->extract_ids_from_string( (string) $value ) );
        }

        return array_values( array_unique( array_filter( $ids ) ) );
    }

    /**
     * @return array<int, string>
     */
    private function extract_ids_from_string( string $value ): array {
        preg_match_all( '/\b(?:GTM-[A-Z0-9_-]+|GT-[A-Z0-9_-]+|G-[A-Z0-9_-]+|AW-\d+)\b/i', $value, $matches );

        return array_values( array_unique( array_map( 'strtoupper', $matches[0] ?? [] ) ) );
    }

    private function contains_google_tag_snippet( string $snippet ): bool {
        return stripos( $snippet, 'googletagmanager.com/gtag/js' ) !== false
            || stripos( $snippet, 'googletagmanager.com/gtm.js' ) !== false
            || (bool) preg_match( '/\b(?:GTM-[A-Z0-9_-]+|GT-[A-Z0-9_-]+|G-[A-Z0-9_-]+|AW-\d+)\b/i', $snippet );
    }

    /**
     * @param array<int, string> $ids
     */
    private function contains_id_prefix( array $ids, string $prefix ): bool {
        foreach ( $ids as $id ) {
            if ( strpos( $id, $prefix ) === 0 ) {
                return true;
            }
        }

        return false;
    }
}
