<?php
if (!defined('ABSPATH')) {
    exit;
}

final class Aysa_SEO_Backend_Adapter
{
    private static $instance = null;
    private $backend = null;

    public static function instance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public static function reset()
    {
        self::$instance = null;
    }

    public function active_backend()
    {
        if ($this->backend !== null) {
            return $this->backend;
        }

        foreach ($this->external_backends() as $key => $backend) {
            if ($this->backend_is_active($backend)) {
                $backend['key'] = $key;
                $backend['mode'] = 'adapter_mode';
                $this->backend = $backend;
                return $this->backend;
            }
        }

        $this->backend = array(
            'key' => 'aysa',
            'label' => 'AYSA',
            'mode' => 'aysa_owned',
            'fields' => $this->native_fields(),
        );

        return $this->backend;
    }

    public function ownership_summary()
    {
        $backend = $this->active_backend();
        $mode = (string) ($backend['mode'] ?? 'aysa_owned');

        return array(
            'mode' => $mode,
            'backend' => (string) ($backend['key'] ?? 'aysa'),
            'backend_label' => (string) ($backend['label'] ?? 'AYSA'),
            'title_meta' => $mode,
            'canonical' => $mode,
            'robots' => $mode,
            'social' => $mode,
            'sitemap' => $this->sitemap_owner(),
            'schema' => $this->schema_owner(),
            'redirects' => $this->redirects_owner(),
        );
    }

    public function should_aysa_output_head()
    {
        $backend = $this->active_backend();
        return (string) ($backend['mode'] ?? 'aysa_owned') === 'aysa_owned';
    }

    public function diagnostics()
    {
        $backend = $this->active_backend();
        $detected = array();
        foreach ($this->external_backends() as $key => $candidate) {
            $detected[] = array(
                'key' => $key,
                'label' => (string) ($candidate['label'] ?? $key),
                'active' => $this->backend_is_active($candidate),
            );
        }

        return array(
            'active_backend' => (string) ($backend['key'] ?? 'aysa'),
            'active_backend_label' => (string) ($backend['label'] ?? 'AYSA'),
            'mode' => (string) ($backend['mode'] ?? 'aysa_owned'),
            'should_aysa_output_head' => $this->should_aysa_output_head(),
            'ownership' => $this->ownership_summary(),
            'detected_backends' => $detected,
        );
    }

    public function get_metadata($object_id, $object_kind = 'post')
    {
        $object_id = intval($object_id);
        $object_kind = $object_kind === 'term' ? 'term' : 'post';
        if ($object_id <= 0) {
            return array();
        }

        $backend = $this->active_backend();
        $fields = isset($backend['fields']) && is_array($backend['fields']) ? $backend['fields'] : $this->native_fields();

        return array(
            'backend' => (string) ($backend['key'] ?? 'aysa'),
            'mode' => (string) ($backend['mode'] ?? 'aysa_owned'),
            'meta_title' => $this->read_field($object_id, $object_kind, $fields, 'title'),
            'meta_description' => $this->read_field($object_id, $object_kind, $fields, 'description'),
            'primary_keyword' => $this->read_field($object_id, $object_kind, $fields, 'focus_keyword'),
            'canonical_url' => $this->read_field($object_id, $object_kind, $fields, 'canonical'),
            'robots' => $this->read_robots($object_id, $object_kind, $fields),
            'social' => array(
                'og_title' => $this->read_field($object_id, $object_kind, $fields, 'og_title'),
                'og_description' => $this->read_field($object_id, $object_kind, $fields, 'og_description'),
                'og_image' => $this->read_field($object_id, $object_kind, $fields, 'og_image'),
                'twitter_title' => $this->read_field($object_id, $object_kind, $fields, 'twitter_title'),
                'twitter_description' => $this->read_field($object_id, $object_kind, $fields, 'twitter_description'),
                'twitter_image' => $this->read_field($object_id, $object_kind, $fields, 'twitter_image'),
            ),
        );
    }

    public function apply_metadata($object_id, $object_kind, array $metadata)
    {
        $object_id = intval($object_id);
        $object_kind = $object_kind === 'term' ? 'term' : 'post';
        if ($object_id <= 0) {
            return array('applied' => false, 'reason' => 'invalid_object_id');
        }

        $backend = $this->active_backend();
        $fields = isset($backend['fields']) && is_array($backend['fields']) ? $backend['fields'] : $this->native_fields();
        $native = $this->native_fields();
        $applied = array();

        foreach ($this->writable_fields() as $field) {
            if (!array_key_exists($field, $metadata)) {
                continue;
            }

            $value = is_scalar($metadata[$field]) ? (string) $metadata[$field] : '';
            $native_key = $this->field_key($native, $object_kind, $field);
            if ($native_key !== '') {
                $this->write_meta($object_id, $object_kind, $native_key, $value);
                $applied['aysa:' . $field] = $native_key;
            }

            $backend_key = $this->field_key($fields, $object_kind, $field);
            if ($backend_key !== '' && $backend_key !== $native_key) {
                $this->write_meta($object_id, $object_kind, $backend_key, $value);
                $applied[(string) ($backend['key'] ?? 'aysa') . ':' . $field] = $backend_key;
            }
        }

        if (isset($metadata['robots']) && is_array($metadata['robots'])) {
            $this->write_robots($object_id, $object_kind, $fields, $metadata['robots'], $applied);
        }

        return array(
            'applied' => !empty($applied),
            'backend' => (string) ($backend['key'] ?? 'aysa'),
            'mode' => (string) ($backend['mode'] ?? 'aysa_owned'),
            'fields' => $applied,
        );
    }

    private function read_field($object_id, $object_kind, array $fields, $field)
    {
        $key = $this->field_key($fields, $object_kind, $field);
        if ($key === '') {
            return '';
        }

        $value = $object_kind === 'term'
            ? get_term_meta($object_id, $key, true)
            : get_post_meta($object_id, $key, true);

        return is_scalar($value) ? trim((string) $value) : '';
    }

    private function write_meta($object_id, $object_kind, $key, $value)
    {
        $value = trim((string) $value);
        if ($value === '') {
            if ($object_kind === 'term') {
                delete_term_meta($object_id, $key);
            } else {
                delete_post_meta($object_id, $key);
            }
            return;
        }

        if ($object_kind === 'term') {
            update_term_meta($object_id, $key, $value);
        } else {
            update_post_meta($object_id, $key, $value);
        }
    }

    private function read_robots($object_id, $object_kind, array $fields)
    {
        $key = $this->field_key($fields, $object_kind, 'robots');
        if ($key === '') {
            return array();
        }

        $value = $object_kind === 'term'
            ? get_term_meta($object_id, $key, true)
            : get_post_meta($object_id, $key, true);

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

        $value = strtolower(trim((string) $value));
        if ($value === '') {
            return array();
        }

        return array('raw' => $value, 'noindex' => strpos($value, 'noindex') !== false);
    }

    private function write_robots($object_id, $object_kind, array $fields, array $robots, array &$applied)
    {
        $key = $this->field_key($fields, $object_kind, 'robots');
        if ($key === '') {
            return;
        }

        if (isset($robots['raw']) && is_array($robots['raw'])) {
            $value = $robots['raw'];
        } elseif (!empty($robots['noindex'])) {
            $value = 'noindex';
        } else {
            $value = '';
        }

        if ($object_kind === 'term') {
            $value === '' ? delete_term_meta($object_id, $key) : update_term_meta($object_id, $key, $value);
        } else {
            $value === '' ? delete_post_meta($object_id, $key) : update_post_meta($object_id, $key, $value);
        }
        $applied['robots'] = $key;
    }

    private function field_key(array $fields, $object_kind, $field)
    {
        $scope = $object_kind === 'term' ? 'term' : 'post';
        if (isset($fields[$scope][$field])) {
            return (string) $fields[$scope][$field];
        }
        if (isset($fields['post'][$field])) {
            return (string) $fields['post'][$field];
        }
        return '';
    }

    private function writable_fields()
    {
        return array(
            'title',
            'description',
            'focus_keyword',
            'canonical',
            'og_title',
            'og_description',
            'og_image',
            'twitter_title',
            'twitter_description',
            'twitter_image',
        );
    }

    private function backend_is_active(array $backend)
    {
        foreach ((array) ($backend['plugin_files'] ?? array()) as $plugin_file) {
            if ($this->plugin_file_is_active($plugin_file)) {
                return true;
            }
        }

        foreach ((array) ($backend['classes'] ?? array()) as $class) {
            if (class_exists($class)) {
                return true;
            }
        }

        foreach ((array) ($backend['functions'] ?? array()) as $function) {
            if (function_exists($function)) {
                return true;
            }
        }

        return false;
    }

    private function plugin_file_is_active($plugin_file)
    {
        $active_plugins = (array) get_option('active_plugins', array());
        if (in_array($plugin_file, $active_plugins, true)) {
            return true;
        }

        if (is_multisite()) {
            $network_plugins = (array) get_site_option('active_sitewide_plugins', array());
            if (isset($network_plugins[$plugin_file])) {
                return true;
            }
        }

        return false;
    }

    private function sitemap_owner()
    {
        $backend = $this->active_backend();
        $key = (string) ($backend['key'] ?? 'aysa');
        return in_array($key, array('yoast', 'rank_math', 'aioseo', 'seopress', 'siteseo'), true) ? 'external_owner' : 'aysa_owned';
    }

    private function schema_owner()
    {
        $backend = $this->active_backend();
        $key = (string) ($backend['key'] ?? 'aysa');
        return in_array($key, array('yoast', 'rank_math', 'aioseo', 'seopress', 'siteseo'), true) ? 'adapter_mode' : 'aysa_owned';
    }

    private function redirects_owner()
    {
        $backend = $this->active_backend();
        $key = (string) ($backend['key'] ?? 'aysa');
        return in_array($key, array('seopress', 'siteseo', 'rank_math'), true) ? 'adapter_mode' : 'aysa_owned';
    }

    private function native_fields()
    {
        return array(
            'post' => array(
                'title' => '_aysa_seo_title',
                'description' => '_aysa_seo_description',
                'focus_keyword' => '_aysa_seo_keywords',
                'canonical' => 'aysa_canonical_url',
                'robots' => 'aysa_robots_meta',
                'og_title' => '_aysa_social_og_title',
                'og_description' => '_aysa_social_og_description',
                'og_image' => '_aysa_social_og_image',
                'twitter_title' => '_aysa_social_twitter_title',
                'twitter_description' => '_aysa_social_twitter_description',
                'twitter_image' => '_aysa_social_twitter_image',
            ),
            'term' => array(
                'title' => '_aysa_seo_title',
                'description' => '_aysa_seo_description',
                'focus_keyword' => '_aysa_seo_keywords',
                'canonical' => 'aysa_canonical_url',
                'robots' => 'aysa_robots_meta',
                'og_title' => '_aysa_social_og_title',
                'og_description' => '_aysa_social_og_description',
                'og_image' => '_aysa_social_og_image',
                'twitter_title' => '_aysa_social_twitter_title',
                'twitter_description' => '_aysa_social_twitter_description',
                'twitter_image' => '_aysa_social_twitter_image',
            ),
        );
    }

    private function external_backends()
    {
        return array(
            'yoast' => array(
                'label' => 'Yoast SEO',
                'plugin_files' => array('wordpress-seo/wp-seo.php'),
                'classes' => array('WPSEO_Options'),
                'fields' => array(
                    'post' => array(
                        'title' => '_yoast_wpseo_title',
                        'description' => '_yoast_wpseo_metadesc',
                        'focus_keyword' => '_yoast_wpseo_focuskw',
                        'canonical' => '_yoast_wpseo_canonical',
                        'robots' => '_yoast_wpseo_meta-robots-noindex',
                        'og_title' => '_yoast_wpseo_opengraph-title',
                        'og_description' => '_yoast_wpseo_opengraph-description',
                        'og_image' => '_yoast_wpseo_opengraph-image',
                        'twitter_title' => '_yoast_wpseo_twitter-title',
                        'twitter_description' => '_yoast_wpseo_twitter-description',
                        'twitter_image' => '_yoast_wpseo_twitter-image',
                    ),
                    'term' => array(
                        'title' => '_yoast_wpseo_title',
                        'description' => '_yoast_wpseo_desc',
                        'focus_keyword' => '_yoast_wpseo_focuskw',
                        'canonical' => '_yoast_wpseo_canonical',
                        'robots' => '_yoast_wpseo_meta-robots-noindex',
                    ),
                ),
            ),
            'rank_math' => array(
                'label' => 'Rank Math',
                'plugin_files' => array('seo-by-rank-math/rank-math.php'),
                'classes' => array('RankMath'),
                'fields' => array(
                    'post' => array(
                        'title' => 'rank_math_title',
                        'description' => 'rank_math_description',
                        'focus_keyword' => 'rank_math_focus_keyword',
                        'canonical' => 'rank_math_canonical_url',
                        'robots' => 'rank_math_robots',
                        'og_title' => 'rank_math_facebook_title',
                        'og_description' => 'rank_math_facebook_description',
                        'og_image' => 'rank_math_facebook_image',
                        'twitter_title' => 'rank_math_twitter_title',
                        'twitter_description' => 'rank_math_twitter_description',
                        'twitter_image' => 'rank_math_twitter_image',
                    ),
                    'term' => array(
                        'title' => 'rank_math_title',
                        'description' => 'rank_math_description',
                        'focus_keyword' => 'rank_math_focus_keyword',
                        'canonical' => 'rank_math_canonical_url',
                        'robots' => 'rank_math_robots',
                    ),
                ),
            ),
            'siteseo' => array(
                'label' => 'SiteSEO',
                'plugin_files' => array('siteseo/siteseo.php'),
                'classes' => array('SiteSEO\\TitlesMetas'),
                'fields' => array(
                    'post' => array(
                        'title' => '_siteseo_titles_title',
                        'description' => '_siteseo_titles_desc',
                        'focus_keyword' => '_siteseo_analysis_target_kw',
                        'canonical' => '_siteseo_robots_canonical',
                        'robots' => '_siteseo_robots_index',
                        'og_title' => '_siteseo_social_fb_title',
                        'og_description' => '_siteseo_social_fb_desc',
                        'og_image' => '_siteseo_social_fb_img',
                        'twitter_title' => '_siteseo_social_twitter_title',
                        'twitter_description' => '_siteseo_social_twitter_desc',
                        'twitter_image' => '_siteseo_social_twitter_img',
                    ),
                    'term' => array(
                        'title' => '_siteseo_titles_title',
                        'description' => '_siteseo_titles_desc',
                        'focus_keyword' => '_siteseo_analysis_target_kw',
                        'canonical' => '_siteseo_robots_canonical',
                        'robots' => '_siteseo_robots_index',
                        'og_title' => '_siteseo_social_fb_title',
                        'og_description' => '_siteseo_social_fb_desc',
                        'og_image' => '_siteseo_social_fb_img',
                        'twitter_title' => '_siteseo_social_twitter_title',
                        'twitter_description' => '_siteseo_social_twitter_desc',
                        'twitter_image' => '_siteseo_social_twitter_img',
                    ),
                ),
            ),
            'seopress' => array(
                'label' => 'SEOPress',
                'plugin_files' => array('wp-seopress/seopress.php'),
                'functions' => array('seopress_init'),
                'fields' => array(
                    'post' => array(
                        'title' => '_seopress_titles_title',
                        'description' => '_seopress_titles_desc',
                        'focus_keyword' => '_seopress_analysis_target_kw',
                        'canonical' => '_seopress_robots_canonical',
                        'robots' => '_seopress_robots_index',
                        'og_title' => '_seopress_social_fb_title',
                        'og_description' => '_seopress_social_fb_desc',
                        'og_image' => '_seopress_social_fb_img',
                        'twitter_title' => '_seopress_social_twitter_title',
                        'twitter_description' => '_seopress_social_twitter_desc',
                        'twitter_image' => '_seopress_social_twitter_img',
                    ),
                    'term' => array(
                        'title' => '_seopress_titles_title',
                        'description' => '_seopress_titles_desc',
                        'focus_keyword' => '_seopress_analysis_target_kw',
                        'canonical' => '_seopress_robots_canonical',
                        'robots' => '_seopress_robots_index',
                    ),
                ),
            ),
            'aioseo' => array(
                'label' => 'All in One SEO',
                'plugin_files' => array('all-in-one-seo-pack/all_in_one_seo_pack.php', 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php'),
                'classes' => array('AIOSEO\\Plugin\\Common\\Main', 'AIOSEO\\Plugin\\AIOSEO'),
                'fields' => array(
                    'post' => array(
                        'title' => '_aioseo_title',
                        'description' => '_aioseo_description',
                        'focus_keyword' => '_aioseo_keywords',
                        'canonical' => '_aioseo_canonical_url',
                        'robots' => '_aioseo_robots_noindex',
                    ),
                    'term' => array(
                        'title' => '_aioseo_title',
                        'description' => '_aioseo_description',
                        'focus_keyword' => '_aioseo_keywords',
                        'canonical' => '_aioseo_canonical_url',
                        'robots' => '_aioseo_robots_noindex',
                    ),
                ),
            ),
        );
    }
}

function aysa_seo_backend_adapter()
{
    return Aysa_SEO_Backend_Adapter::instance();
}
