<?php

declare(strict_types=1);


/**
 * Site Basics Frontend Output
 *
 * Handles outputting site basics meta tags and data to the frontend
 *
 * @package ProRank\SEO\Frontend
 * @since 1.0.0
 */

namespace ProRank\SEO\Frontend;

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


/**
 * Site Basics Output class
 */


class SiteBasicsOutput {

    /**
     * Settings array
     *
     * @var array
     */
    private $settings = [];

    /**
     * Constructor
     */
    public function __construct() {
        $this->init();
    }

    /**
     * Initialize the class
     */
    public function init() {
        // Load settings
        $this->settings = get_option('prorank_seo_site_basics', []);

        // Verification tags and social account meta are sourced from Site Basics.
        add_action("wp_head", function() {
            try {
                $this->output_meta_tags();
            } catch (\Throwable $e) {
                if (function_exists('prorank_log')) {
                    prorank_log('[ProRank SiteBasicsOutput] verification meta failed: ' . $e->getMessage());
                }
            }
        }, 1);
        add_action("wp_head", function() {
            try {
                $this->output_social_meta();
            } catch (\Throwable $e) {
                if (function_exists('prorank_log')) {
                    prorank_log('[ProRank SiteBasicsOutput] social meta failed: ' . $e->getMessage());
                }
            }
        }, 2);
        add_action("wp_head", function() {
            try {
                $this->output_tracking_tags();
            } catch (\Throwable $e) {
                if (function_exists('prorank_log')) {
                    prorank_log('[ProRank SiteBasicsOutput] tracking tags failed: ' . $e->getMessage());
                }
            }
        }, 20);
        add_action("wp_body_open", function() {
            try {
                $this->output_gtm_noscript();
            } catch (\Throwable $e) {
                if (function_exists('prorank_log')) {
                    prorank_log('[ProRank SiteBasicsOutput] GTM noscript failed: ' . $e->getMessage());
                }
            }
        }, 1);
    }

    /**
     * Output verification meta tags
     */
    public function output_meta_tags() {
        static $output_done = false;
        if ($output_done) return;
        $output_done = true;
        // Only output on homepage for verification tags
        if (!is_front_page() && !is_home()) {
            return;
        }

        // Google Site Verification
        if (!empty($this->settings['google_verification'])) {
            printf(
                '<meta name="google-site-verification" content="%s" />' . "\n",
                esc_attr($this->settings['google_verification'])
            );
        }

        // Bing Verification
        if (!empty($this->settings['bing_verification'])) {
            printf(
                '<meta name="msvalidate.01" content="%s" />' . "\n",
                esc_attr($this->settings['bing_verification'])
            );
        }

        // Baidu Verification
        if (!empty($this->settings['baidu_verification'])) {
            printf(
                '<meta name="baidu-site-verification" content="%s" />' . "\n",
                esc_attr($this->settings['baidu_verification'])
            );
        }

        // Yandex Verification
        if (!empty($this->settings['yandex_verification'])) {
            printf(
                '<meta name="yandex-verification" content="%s" />' . "\n",
                esc_attr($this->settings['yandex_verification'])
            );
        }

        // Pinterest Verification
        if (!empty($this->settings['pinterest_verification'])) {
            printf(
                '<meta name="p:domain_verify" content="%s" />' . "\n",
                esc_attr($this->settings['pinterest_verification'])
            );
        }

        // Norton Safe Web Verification
        if (!empty($this->settings['norton_verification'])) {
            printf(
                '<meta name="norton-safeweb-site-verification" content="%s" />' . "\n",
                esc_attr($this->settings['norton_verification'])
            );
        }

        // Custom meta tags
        if (!empty($this->settings['custom_meta_tags'])) {
            $allowed_tags = [
                'meta' => [
                    'name' => true,
                    'content' => true,
                    'property' => true,
                    'http-equiv' => true,
                    'charset' => true,
                ],
            ];
            preg_match_all('/<meta\b[^>]*>/i', (string) $this->settings['custom_meta_tags'], $matches);
            foreach ($matches[0] ?? [] as $tag) {
                $clean = trim((string) wp_kses($tag, $allowed_tags));
                if ($clean !== '') {
                    echo $clean . "\n";
                }
            }
        }
    }

    /**
     * Output social media meta tags
     */
    public function output_social_meta() {
        // Facebook App ID
        if (!empty($this->settings['facebook_app_id'])) {
            printf(
                '<meta property="fb:app_id" content="%s" />' . "\n",
                esc_attr($this->settings['facebook_app_id'])
            );
        }

        // Facebook Admin ID
        if (!empty($this->settings['facebook_admin_id'])) {
            printf(
                '<meta property="fb:admins" content="%s" />' . "\n",
                esc_attr($this->settings['facebook_admin_id'])
            );
        }

        // Twitter Creator (if set)
        if (!empty($this->settings['twitter_username'])) {
            $username = $this->settings['twitter_username'];
            // Add @ if not present
            if (strpos($username, '@') !== 0) {
                $username = '@' . $username;
            }
            printf(
                '<meta name="twitter:creator" content="%s" />' . "\n",
                esc_attr($username)
            );
        }
    }

    /**
     * Output generated analytics and tag manager snippets.
     */
    public function output_tracking_tags(): void {
        static $output_done = false;
        if ($output_done) {
            return;
        }
        $output_done = true;

        $gtm_id = $this->normalize_gtm_id((string) ($this->settings['google_tag_manager_id'] ?? ''));
        if ($gtm_id !== '') {
            $this->output_gtm_head($gtm_id);
        }

        $ga4_id = $this->normalize_ga4_id((string) ($this->settings['ga4_measurement_id'] ?? ''));
        if ($ga4_id !== '') {
            $this->output_ga4_tag($ga4_id);
        }
    }

    /**
     * Output Google Tag Manager noscript fallback immediately after body open.
     */
    public function output_gtm_noscript(): void {
        static $output_done = false;
        if ($output_done) {
            return;
        }
        $output_done = true;

        $gtm_id = $this->normalize_gtm_id((string) ($this->settings['google_tag_manager_id'] ?? ''));
        if ($gtm_id === '') {
            return;
        }

        $iframe_url = add_query_arg(
            'id',
            rawurlencode($gtm_id),
            'https://www.googletagmanager.com/ns.html'
        );

        printf(
            '<noscript><iframe src="%s" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>' . "\n",
            esc_url($iframe_url)
        );
    }

    /**
     * Output the Google Tag Manager head snippet.
     *
     * @param string $gtm_id Sanitized GTM container ID.
     */
    private function output_gtm_head(string $gtm_id): void {
        echo "<script>\n";
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Static GTM bootstrap with sanitized container ID.
        echo "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer'," . wp_json_encode($gtm_id) . ");\n";
        echo "</script>\n";
    }

    /**
     * Output the Google Analytics 4 gtag snippet.
     *
     * @param string $ga4_id Sanitized GA4 measurement ID.
     */
    private function output_ga4_tag(string $ga4_id): void {
        $script_url = add_query_arg(
            'id',
            rawurlencode($ga4_id),
            'https://www.googletagmanager.com/gtag/js'
        );

        printf('<script async src="%s"></script>' . "\n", esc_url($script_url));
        echo "<script>\n";
        echo "window.dataLayer = window.dataLayer || [];\n";
        echo "function gtag(){dataLayer.push(arguments);}\n";
        echo "gtag('js', new Date());\n";
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Measurement ID is regex-sanitized and JSON encoded.
        echo "gtag('config', " . wp_json_encode($ga4_id) . ");\n";
        echo "</script>\n";
    }

    /**
     * Normalize a GA4 measurement ID.
     *
     * @param string $value Raw ID or pasted tag.
     * @return string
     */
    private function normalize_ga4_id(string $value): string {
        if (preg_match('/\bG-[A-Z0-9]{4,}\b/i', $value, $matches) !== 1) {
            return '';
        }

        return strtoupper($matches[0]);
    }

    /**
     * Normalize a Google Tag Manager container ID.
     *
     * @param string $value Raw ID or pasted tag.
     * @return string
     */
    private function normalize_gtm_id(string $value): string {
        if (preg_match('/\bGTM-[A-Z0-9]{4,}\b/i', $value, $matches) !== 1) {
            return '';
        }

        return strtoupper($matches[0]);
    }

    /**
     * Output organization/person schema markup
     */
    public function output_organization_schema() {
        // Only output on homepage
        if (!is_front_page() && !is_home()) {
            return;
        }

        $schema = [];

        if (isset($this->settings['org_or_person']) && $this->settings['org_or_person'] === 'organization') {
            $schema = $this->build_organization_schema();
        } elseif (isset($this->settings['org_or_person']) && $this->settings['org_or_person'] === 'person') {
            $schema = $this->build_person_schema();
        }

        if (!empty($schema)) {
            echo '<script type="application/ld+json">' . "\n";
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON-LD script body.
            echo wp_json_encode($schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            echo "\n" . '</script>' . "\n";
        }
    }

    /**
     * Build organization schema
     */
    private function build_organization_schema() {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'Organization',
        ];

        // Name (prefer selected user)
        if (!empty($this->settings['person_user_id'])) {
            $user = get_user_by('id', (int) $this->settings['person_user_id']);
            if ($user && !empty($user->display_name)) {
                $schema['name'] = $user->display_name;
            }
        }
        if (empty($schema['name']) && !empty($this->settings['org_name'])) {
            $schema['name'] = $this->settings['org_name'];
        } elseif (empty($schema['name']) && !empty($this->settings['site_name'])) {
            $schema['name'] = $this->settings['site_name'];
        } elseif (empty($schema['name'])) {
            $schema['name'] = get_bloginfo('name');
        }

        // Alternate name
        if (!empty($this->settings['org_alternate_name'])) {
            $schema['alternateName'] = $this->settings['org_alternate_name'];
        } elseif (!empty($this->settings['site_alternate_name'])) {
            $schema['alternateName'] = $this->settings['site_alternate_name'];
        }

        // URL
        $schema['url'] = home_url('/');

        // Logo
        if (!empty($this->settings['org_logo'])) {
            $schema['logo'] = $this->settings['org_logo'];
        } elseif (!empty($this->settings['site_logo'])) {
            $schema['logo'] = $this->settings['site_logo'];
        }

        // Description
        if (!empty($this->settings['org_description'])) {
            $schema['description'] = $this->settings['org_description'];
        } elseif (!empty($this->settings['site_tagline'])) {
            $schema['description'] = $this->settings['site_tagline'];
        }

        // Contact info
        if (!empty($this->settings['org_email']) || !empty($this->settings['org_phone'])) {
            $contactPoint = [
                '@type' => 'ContactPoint',
                'contactType' => 'customer service',
            ];

            if (!empty($this->settings['org_email'])) {
                $contactPoint['email'] = $this->settings['org_email'];
            }

            if (!empty($this->settings['org_phone'])) {
                $contactPoint['telephone'] = $this->settings['org_phone'];
            }

            $schema['contactPoint'] = $contactPoint;
        }

        // Address
        if (!empty($this->settings['org_street_address']) ||
            !empty($this->settings['org_address_locality']) ||
            !empty($this->settings['org_address_region']) ||
            !empty($this->settings['org_postal_code']) ||
            !empty($this->settings['org_address_country'])) {

            $address = [
                '@type' => 'PostalAddress',
            ];

            if (!empty($this->settings['org_street_address'])) {
                $address['streetAddress'] = $this->settings['org_street_address'];
            }

            if (!empty($this->settings['org_address_locality'])) {
                $address['addressLocality'] = $this->settings['org_address_locality'];
            }

            if (!empty($this->settings['org_address_region'])) {
                $address['addressRegion'] = $this->settings['org_address_region'];
            }

            if (!empty($this->settings['org_postal_code'])) {
                $address['postalCode'] = $this->settings['org_postal_code'];
            }

            if (!empty($this->settings['org_address_country'])) {
                $address['addressCountry'] = $this->settings['org_address_country'];
            }

            $schema['address'] = $address;
        }

        // Social profiles
        $sameAs = [];

        if (!empty($this->settings['facebook_page_url'])) {
            $sameAs[] = $this->settings['facebook_page_url'];
        }
        if (!empty($this->settings['twitter_username'])) {
            $sameAs[] = 'https://twitter.com/' . ltrim($this->settings['twitter_username'], '@');
        }
        if (!empty($this->settings['linkedin_url'])) {
            $sameAs[] = $this->settings['linkedin_url'];
        }
        if (!empty($this->settings['instagram_url'])) {
            $sameAs[] = $this->settings['instagram_url'];
        }
        if (!empty($this->settings['youtube_url'])) {
            $sameAs[] = $this->settings['youtube_url'];
        }
        if (!empty($this->settings['pinterest_url'])) {
            $sameAs[] = $this->settings['pinterest_url'];
        }
        if (!empty($this->settings['tiktok_url'])) {
            $sameAs[] = $this->settings['tiktok_url'];
        }
        if (!empty($this->settings['threads_url'])) {
            $sameAs[] = $this->settings['threads_url'];
        }
        if (!empty($this->settings['mastodon_url'])) {
            $sameAs[] = $this->settings['mastodon_url'];
        }

        // Additional profiles
        if (!empty($this->settings['additional_profiles']) && is_array($this->settings['additional_profiles'])) {
            foreach ($this->settings['additional_profiles'] as $profile) {
                if (!empty($profile['url'])) {
                    $sameAs[] = $profile['url'];
                }
            }
        }

        if (!empty($sameAs)) {
            $schema['sameAs'] = $sameAs;
        }

        // Additional organization properties
        if (!empty($this->settings['org_founding_date'])) {
            $schema['foundingDate'] = $this->settings['org_founding_date'];
        }

        if (!empty($this->settings['org_legal_name'])) {
            $schema['legalName'] = $this->settings['org_legal_name'];
        }

        if (!empty($this->settings['org_vat_id'])) {
            $schema['vatID'] = $this->settings['org_vat_id'];
        }

        if (!empty($this->settings['org_tax_id'])) {
            $schema['taxID'] = $this->settings['org_tax_id'];
        }

        if (!empty($this->settings['org_iso_6523'])) {
            $schema['iso6523Code'] = $this->settings['org_iso_6523'];
        }

        if (!empty($this->settings['org_duns'])) {
            $schema['duns'] = $this->settings['org_duns'];
        }

        if (!empty($this->settings['org_lei_code'])) {
            $schema['leiCode'] = $this->settings['org_lei_code'];
        }

        if (!empty($this->settings['org_naics'])) {
            $schema['naics'] = $this->settings['org_naics'];
        }

        if (!empty($this->settings['org_num_employees'])) {
            $schema['numberOfEmployees'] = [
                '@type' => 'QuantitativeValue',
                'value' => $this->settings['org_num_employees']
            ];
        }

        // Publishing principles (for news/media sites)
        $publishingPrinciples = [];

        if (!empty($this->settings['publishing_principles_page'])) {
            $publishingPrinciples[] = get_permalink($this->settings['publishing_principles_page']);
        }
        if (!empty($this->settings['corrections_policy_page'])) {
            $publishingPrinciples[] = get_permalink($this->settings['corrections_policy_page']);
        }
        if (!empty($this->settings['ethics_policy_page'])) {
            $publishingPrinciples[] = get_permalink($this->settings['ethics_policy_page']);
        }
        if (!empty($this->settings['diversity_policy_page'])) {
            $publishingPrinciples[] = get_permalink($this->settings['diversity_policy_page']);
        }

        if (!empty($publishingPrinciples)) {
            $schema['publishingPrinciples'] = $publishingPrinciples;
        }

        if (!empty($this->settings['ownership_funding_page'])) {
            $schema['ownershipFundingInfo'] = get_permalink($this->settings['ownership_funding_page']);
        }

        if (!empty($this->settings['actionable_feedback_page'])) {
            $schema['actionableFeedbackPolicy'] = get_permalink($this->settings['actionable_feedback_page']);
        }

        if (!empty($this->settings['diversity_staffing_page'])) {
            $schema['diversityStaffingReport'] = get_permalink($this->settings['diversity_staffing_page']);
        }

        // Privacy policy
        if (!empty($this->settings['privacy_policy_page'])) {
            $schema['privacyPolicy'] = get_permalink($this->settings['privacy_policy_page']);
        }

        // Terms of service
        if (!empty($this->settings['terms_of_service_page'])) {
            $schema['termsOfService'] = get_permalink($this->settings['terms_of_service_page']);
        }

        return $schema;
    }

    /**
     * Build person schema
     */
    private function build_person_schema() {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'Person',
        ];

        // Name
        if (!empty($this->settings['org_name'])) {
            $schema['name'] = $this->settings['org_name'];
        } elseif (!empty($this->settings['site_name'])) {
            $schema['name'] = $this->settings['site_name'];
        } else {
            $schema['name'] = get_bloginfo('name');
        }

        // URL
        $schema['url'] = home_url('/');

        // Image
        if (!empty($this->settings['person_logo'])) {
            $schema['image'] = $this->settings['person_logo'];
        } elseif (!empty($this->settings['person_logo_id'])) {
            $person_logo_url = wp_get_attachment_url((int) $this->settings['person_logo_id']);
            if (!empty($person_logo_url)) {
                $schema['image'] = $person_logo_url;
            }
        } elseif (!empty($this->settings['person_user_id'])) {
            $avatar_url = get_avatar_url((int) $this->settings['person_user_id']);
            if (!empty($avatar_url)) {
                $schema['image'] = $avatar_url;
            }
        } elseif (!empty($this->settings['org_logo'])) {
            $schema['image'] = $this->settings['org_logo'];
        } elseif (!empty($this->settings['site_logo'])) {
            $schema['image'] = $this->settings['site_logo'];
        }

        // Description
        if (!empty($this->settings['org_description'])) {
            $schema['description'] = $this->settings['org_description'];
        } elseif (!empty($this->settings['site_tagline'])) {
            $schema['description'] = $this->settings['site_tagline'];
        }

        // Email
        if (!empty($this->settings['org_email'])) {
            $schema['email'] = $this->settings['org_email'];
        }

        // Phone
        if (!empty($this->settings['org_phone'])) {
            $schema['telephone'] = $this->settings['org_phone'];
        }

        // Social profiles
        $sameAs = [];

        if (!empty($this->settings['facebook_authorship'])) {
            $sameAs[] = $this->settings['facebook_authorship'];
        } elseif (!empty($this->settings['facebook_page_url'])) {
            $sameAs[] = $this->settings['facebook_page_url'];
        }

        if (!empty($this->settings['twitter_username'])) {
            $sameAs[] = 'https://twitter.com/' . ltrim($this->settings['twitter_username'], '@');
        }
        if (!empty($this->settings['linkedin_url'])) {
            $sameAs[] = $this->settings['linkedin_url'];
        }
        if (!empty($this->settings['instagram_url'])) {
            $sameAs[] = $this->settings['instagram_url'];
        }
        if (!empty($this->settings['youtube_url'])) {
            $sameAs[] = $this->settings['youtube_url'];
        }
        if (!empty($this->settings['pinterest_url'])) {
            $sameAs[] = $this->settings['pinterest_url'];
        }
        if (!empty($this->settings['tiktok_url'])) {
            $sameAs[] = $this->settings['tiktok_url'];
        }
        if (!empty($this->settings['threads_url'])) {
            $sameAs[] = $this->settings['threads_url'];
        }
        if (!empty($this->settings['mastodon_url'])) {
            $sameAs[] = $this->settings['mastodon_url'];
        }
        if (!empty($this->settings['additional_profiles']) && is_array($this->settings['additional_profiles'])) {
            foreach ($this->settings['additional_profiles'] as $profile) {
                if (!empty($profile['url'])) {
                    $sameAs[] = $profile['url'];
                }
            }
        }

        if (!empty($sameAs)) {
            $schema['sameAs'] = $sameAs;
        }

        return $schema;
    }
}
