<?php

if (! defined('ABSPATH')) {
    exit;
} class PufferGo_Schema
{
    public const ORG_FRAGMENT = '#organization';

    public static function init(): void
    {
        add_filter('rank_math/json_ld', array(__CLASS__, 'enrich_graph'), 20, 2);
        add_filter('rank_math/schema/language', array(__CLASS__, 'filter_language'));
    }

    public static function filter_language($language)
    {
        if (! class_exists('PufferGo_Polylang') || ! PufferGo_Polylang::is_active()) {
            return $language;
        } $slug = PufferGo_Polylang::current_language();

        if ('' === $slug) {
            return $language;
        } $tag = self::locale_to_bcp47(PufferGo_Polylang::locale_for($slug));

        if ('' === $tag) {
            return $language;
        } $base = strtok($tag, '-');
        $sharing = 0;

        foreach (PufferGo_Polylang::languages() as $configured) {
            $other = self::locale_to_bcp47($configured['locale']);

            if ('' !== $other && strtok($other, '-') === $base) {
                ++$sharing;
            }
        }

return $sharing > 1 ? $tag : $base;
    }

    private static function locale_to_bcp47(string $locale): string
    {
        return str_replace('_', '-', trim($locale));
    }

    public static function organization_id(): string
    {
        $home = trailingslashit(home_url('/'));

        if (class_exists('PufferGo_Polylang') && PufferGo_Polylang::is_active()) {
            $default = PufferGo_Polylang::default_language();

            if ('' !== $default) {
                $home = PufferGo_Polylang::home_url($default);
            }
        } $scheme = wp_parse_url(home_url('/'), PHP_URL_SCHEME);

        return set_url_scheme($home, is_string($scheme) ? $scheme : null) . self::ORG_FRAGMENT;
    }

    public static function enrich_graph($data, $jsonld = null)
    {
        if (! is_array($data)) {
            return $data;
        } $profile = self::get_profile();

        if (empty($profile)) {
            return $data;
        } $existing = (isset($data['publisher']) && is_array($data['publisher'])) ? $data['publisher'] : array();

        if (empty($existing) && ! self::can_add_global_entities($data, $jsonld)) {
            return $data;
        } $entity = ! empty($existing) ? $existing : array('url' => home_url('/'));
        $old_id = isset($entity['@id']) ? (string) $entity['@id'] : '';
        $entity['@type'] = self::organization_type($entity);
        $entity['@id'] = self::organization_id();
        self::apply_identity($entity, $profile);
        self::apply_contact($entity, $profile);
        self::apply_trust($entity, $profile);
        self::apply_certifications($entity, $profile);

        if (empty($existing) && empty($entity['name'])) {
            return $data;
        } $data['publisher'] = $entity;

        if ('' !== $old_id && $old_id !== $entity['@id']) {
            $data = self::rewrite_id_references($data, $old_id, $entity['@id']);
        }

return $data;
    }

    private static function can_add_global_entities(array $data, $jsonld): bool
    {
        if (! is_object($jsonld) || ! method_exists($jsonld, 'can_add_global_entities')) {
            return false;
        } unset($data['publisher']);

        return (bool) $jsonld->can_add_global_entities($data);
    }

    private static function organization_type(array $entity)
    {
        $types = isset($entity['@type']) ? (array) $entity['@type'] : array();
        $types = array_values(array_filter($types, static function ($type) { return 'Person' !== $type && '' !== $type; }));

        if (empty($types)) {
            return 'Organization';
        }

return 1 === count($types) ? $types[0] : $types;
    }

    private static function apply_identity(array &$entity, array $profile): void
    {
        $identity = self::section($profile, 'identity');
        $configured = self::rank_math_setting('titles.knowledgegraph_name');

        if ('' !== $configured) {
            self::fill_text($entity, 'name', $configured);
        } else {
            self::set_text($entity, 'name', $identity['brand_name'] ?? '');
        } self::fill_text($entity, 'slogan', $identity['slogan'] ?? '');
        self::fill_text($entity, 'description', $identity['story'] ?? '');
        $founded = self::normalize_founding_date($identity['founded'] ?? '');

        if ('' !== $founded) {
            self::fill_text($entity, 'foundingDate', $founded);
        }
    }

    private static function apply_contact(array &$entity, array $profile): void
    {
        $contact = self::section($profile, 'contact');
        self::fill_text($entity, 'telephone', $contact['phone'] ?? '');
        self::fill_text($entity, 'email', $contact['email'] ?? '');
        self::fill_text($entity, 'address', $contact['address'] ?? '');
        $audience = self::section($profile, 'audience');
        $regions = self::split_list($audience['regions'] ?? '');

        if (! empty($regions) && empty($entity['areaServed'])) {
            $entity['areaServed'] = $regions;
        } $assets = self::section($profile, 'assets');
        $logo = isset($assets['logo_url']) ? trim((string) $assets['logo_url']) : '';

        if ('' !== $logo && empty($entity['logo'])) {
            $entity['logo'] = $logo;
        }
    }

    private static function apply_trust(array &$entity, array $profile): void
    {
        if (! empty($entity['numberOfEmployees'])) {
            return;
        } $trust = self::section($profile, 'trustData');
        $raw = isset($trust['employees']) ? trim((string) $trust['employees']) : '';

        if ('' === $raw) {
            return;
        } $normalized = str_replace(array('–', '~', '至'), '-', $raw);
        $normalized = preg_replace('/[,\s]/u', '', $normalized);

        if (preg_match('/^(\d+)-(\d+)$/', (string) $normalized, $matches)) {
            $entity['numberOfEmployees'] = array('@type' => 'QuantitativeValue', 'minValue' => (int) $matches[1], 'maxValue' => (int) $matches[2], );

            return;
        }

if (preg_match('/^(\d+)\+?$/', (string) $normalized, $matches)) {
            $entity['numberOfEmployees'] = array('@type' => 'QuantitativeValue', 'value' => (int) $matches[1], );
        }
    }

    private static function apply_certifications(array &$entity, array $profile): void
    {
        if (! empty($entity['hasCertification'])) {
            return;
        } $advantage = self::section($profile, 'advantage');
        $raw = isset($advantage['certifications']) ? (array) $advantage['certifications'] : array();
        $certifications = array();

        foreach ($raw as $item) {
            if (! is_array($item)) {
                continue;
            } $name = isset($item['name']) ? trim((string) $item['name']) : '';

            if ('' === $name) {
                continue;
            } $certification = array('@type' => 'Certification', 'name' => $name, );
            $issuer = isset($item['issuer']) ? trim((string) $item['issuer']) : '';

            if ('' !== $issuer) {
                $certification['issuedBy'] = array('@type' => 'Organization', 'name' => $issuer, );
            } $scope = isset($item['scope']) ? trim((string) $item['scope']) : '';

            if ('' !== $scope) {
                $certification['about'] = $scope;
            } $certifications[] = $certification;
        }

if (! empty($certifications)) {
            $entity['hasCertification'] = $certifications;
        }
    }

    private static function get_profile(): array
    {
        if (! class_exists('PufferGo_Site_Profile')) {
            return array();
        } $stored = get_option(PufferGo_Site_Profile::OPTION_KEY, array());

        if (! is_array($stored) || empty($stored)) {
            return array();
        }

return array_replace_recursive(PufferGo_Site_Profile::default_structure(), $stored);
    }

    private static function section(array $profile, string $key): array
    {
        return (isset($profile[ $key ]) && is_array($profile[ $key ])) ? $profile[ $key ] : array();
    }

    private static function rank_math_setting(string $key): string
    {
        if (! class_exists('\RankMath\Helper')) {
            return '';
        } $value = \RankMath\Helper::get_settings($key);

        return is_string($value) ? trim($value) : '';
    }

    private static function set_text(array &$entity, string $key, $value): void
    {
        $value = is_string($value) ? trim($value) : '';

        if ('' !== $value) {
            $entity[ $key ] = $value;
        }
    }

    private static function fill_text(array &$entity, string $key, $value): void
    {
        if (! empty($entity[ $key ])) {
            return;
        } self::set_text($entity, $key, $value);
    }

    private static function split_list($value): array
    {
        if (! is_string($value) || '' === trim($value)) {
            return array();
        } $parts = preg_split('/[,，、;；\/]+/u', $value);

        if (! is_array($parts)) {
            return array();
        } $items = array();

        foreach ($parts as $part) {
            $part = trim($part);

            if ('' !== $part) {
                $items[] = $part;
            }
        }

return array_values(array_unique($items));
    }

    private static function normalize_founding_date($value): string
    {
        if (! is_string($value)) {
            return '';
        } $value = trim($value);

        if ('' === $value) {
            return '';
        }

if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value, $matches)) {
            return self::is_sane_year((int) $matches[1]) ? $value : '';
        }

if (preg_match('/^(\d{4})\s*年?$/u', $value, $matches)) {
            return self::is_sane_year((int) $matches[1]) ? $matches[1] : '';
        }

return '';
    }

    private static function is_sane_year(int $year): bool
    {
        return $year >= 1800 && $year <= (int) gmdate('Y');
    }

    private static function rewrite_id_references($node, string $old, string $new)
    {
        if (! is_array($node)) {
            return $node;
        }

foreach ($node as $key => $value) {
            if ('@id' === $key && is_string($value) && $value === $old) {
                $node[ $key ] = $new;
                continue;
            } $node[ $key ] = self::rewrite_id_references($value, $old, $new);
        }

return $node;
    }
}
