<?php
/**
 * Backlink Agent — SearchShifter Authority
 *
 * Discovers → verifies → logs AI-visible backlinks
 * with evidence attachments.
 *
 * Uses M5 Backlink Framework for database storage:
 *  - ss_log_backlink (hook)
 *  - SS_Backlinks::add_evidence
 *
 * Authority-only module.
 */

if (! defined('__DIR__')) {
    // noop for linting — ABSPATH check below is the actual gate.
}

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

/** AUTHORITY PLAN ONLY */
if (function_exists('ss_is_authority') && ! ss_is_authority()) {
    return;
}

if (!class_exists('SS_Backlink_Agent')) :

class SS_Backlink_Agent {

    const DIR = WP_PLUGIN_DIR . '/searchshifter/data/backlinks';

    /**
     * Instance holder
     * @var SS_Backlink_Agent|null
     */
    protected static $instance = null;

    /**
     * Create and return the singleton instance.
     * Called by SS_Setup via init() or will auto-init when file included (if desired).
     */
    public static function init() {
        if ( self::$instance === null ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Static menu callback shim for setups that register a menu using
     * ['SS_Backlink_Agent', 'render_admin_page'].
     */
    public static function render_admin_page() {
        $inst = self::init();
        $inst->page_html();
    }

    public function __construct() {
        // Only attach admin menu when in WP Admin
        if ( is_admin() ) {
            add_action('admin_menu', [$this, 'admin_page']);
        }

        // AJAX (authenticated)
        add_action('wp_ajax_ss_backlink_scan', [$this, 'ajax_scan']);

        // Cron hook
        add_action('ss_backlink_scan_cron', [$this, 'run_scan']);
        if ( ! wp_next_scheduled('ss_backlink_scan_cron') ) {
            wp_schedule_event( time(), 'hourly', 'ss_backlink_scan_cron' );
        }

        // Ensure data dir exists
        if ( ! file_exists( self::DIR ) ) {
            wp_mkdir_p( self::DIR );
        }
    }

    /** ------------------------------------
     * ADMIN: register submenu
     * ------------------------------------*/
    public function admin_page() {
        // parent slug may differ — adjust to your plugin main slug
        add_submenu_page(
            'searchshifter-main',
            'Backlink Agent',
            'Backlink Agent',
            'manage_options',
            'ss-backlink-agent',
            [$this, 'page_html']
        );
    }

    /** ------------------------------------
     * Admin page HTML
     * ------------------------------------*/
    public function page_html() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( __('Permission denied', 'searchshifter') );
        }
        $nonce = wp_create_nonce('ss_backlink_scan');
        ?>
        <div class="wrap">
            <h1>Backlink Agent</h1>
            <p>Discover → verify → log AI-visible backlinks with evidence.</p>

            <p>
                <button id="ss_bl_btn" class="button button-primary">Run Backlink Scan</button>
                <span id="ss_bl_spinner" style="display:none;margin-left:10px;">Running…</span>
            </p>

            <pre id="ss_bl_out" style="margin-top:20px;background:#111;color:#0f0;padding:15px;white-space:pre-wrap;word-break:break-word;"></pre>

            <script>
            (function($){
                $('#ss_bl_btn').on('click', function(){
                    $('#ss_bl_out').text('');
                    $('#ss_bl_spinner').show();
                    $.post(ajaxurl, {
                        action: 'ss_backlink_scan',
                        _nonce: '<?php echo esc_js($nonce); ?>'
                    }, function(res){
                        $('#ss_bl_spinner').hide();
                        $('#ss_bl_out').text(JSON.stringify(res, null, 2));
                    }).fail(function(xhr){
                        $('#ss_bl_spinner').hide();
                        var txt = 'Request failed: ' + (xhr.responseText || xhr.statusText || 'Unknown');
                        $('#ss_bl_out').text(txt);
                    });
                });
            })(jQuery);
            </script>
        </div>
        <?php
    }

    /** ------------------------------------
     * AJAX endpoint
     * ------------------------------------*/
    public function ajax_scan() {
        if ( ! current_user_can('manage_options') ) {
            wp_send_json_error(['error' => 'Permission denied'], 403);
        }

        if ( ! check_ajax_referer('ss_backlink_scan', '_nonce', false) ) {
            wp_send_json_error(['error' => 'Invalid nonce'], 400);
        }

        $res = $this->run_scan();

        if ( is_wp_error($res) ) {
            wp_send_json_error(['error' => $res->get_error_message()], 500);
        }

        wp_send_json_success($res);
    }

    /** ------------------------------------
     * MAIN pipeline
     * ------------------------------------*/
    public function run_scan() {
        $domain = parse_url( home_url(), PHP_URL_HOST );
        if ( ! $domain ) {
            return new WP_Error('no_domain', 'Could not determine site domain.');
        }

        $serp_key = defined('SS_SERPAPI_KEY') ? SS_SERPAPI_KEY : '';
        if ( empty($serp_key) && function_exists('ss_get_option') ) {
            $serp_key = ss_get_option('serpapi_key');
        }

        if ( ! $serp_key ) {
            return ['error' => 'SS_SERPAPI_KEY missing'];
        }

        // STEP 1 — Discover backlinks
        $found = $this->discover( $domain, $serp_key );

        // STEP 2 — Verify backlinks
        $verified = [];
        foreach ( $found as $row ) {
            $verified[] = $this->verify( $row );
        }

        // STEP 3 — Log into M5 DB + Save evidence
        $saved = [];
        foreach ( $verified as $row ) {
            if ( empty($row['verified']) ) continue;

            // Use filter/hook to store — this returns the inserted ID in your M5 implementation
            $id = apply_filters('ss_log_backlink',
                $row['target'],
                $row['source'],
                [
                    'anchor_text'   => $row['anchor'],
                    'visible_to_ai' => 1
                ]
            );

            // If the site didn't return an ID, try to log via SS_Backlinks->record_backlink as fallback
            if ( ! $id && class_exists('SS_Backlinks') && method_exists('SS_Backlinks','record_backlink') ) {
                $id = SS_Backlinks::record_backlink($row['target'], $row['source'], [
                    'anchor_text' => $row['anchor'],
                    'visible_to_ai' => 1
                ]);
            }

            if ( $id ) {
                $this->save_evidence( $id, $row );
                $saved[] = $row['source'];
            } else {
                error_log("[SS Backlink Agent] Failed to save backlink for {$row['source']}");
            }
        }

        return [
            'domain'   => $domain,
            'found'    => count($found),
            'verified' => count(array_filter($verified, function($r){ return !empty($r['verified']); })),
            'saved'    => $saved
        ];
    }

    /** ------------------------------------
     * Discover via SerpAPI (link:)
     * ------------------------------------*/
    private function discover($domain, $key) {
        $url = "https://serpapi.com/search.json?engine=google&q=" . rawurlencode("link:{$domain}") . "&api_key=" . rawurlencode($key);
        $json = $this->get_json($url);

        if (!$json || empty($json['organic_results'])) {
            return [];
        }

        $output = [];

        foreach ($json['organic_results'] as $r) {
            $source = isset($r['link']) ? $r['link'] : '';
            $anchor = isset($r['title']) ? $r['title'] : '';
            $output[] = [
                'source' => $source,
                'anchor' => $anchor,
                'target' => "https://{$domain}/"
            ];
        }

        return $output;
    }

    /** ------------------------------------
     * Verify link present on source page
     * ------------------------------------*/
    private function verify($row) {
        $row = (array) $row;
        $row['verified'] = false;
        $row['html_snippet'] = '';

        if ( empty($row['source']) || empty($row['target']) ) {
            return $row;
        }

        $html = $this->get($row['source']);
        if ( $html ) {
            $row['verified'] = ( stripos($html, $row['target']) !== false );
            $row['html_snippet'] = $row['verified'] ? wp_trim_words( strip_tags(substr($html, 0, 1200)), 60, '...' ) : '';
        }

        return $row;
    }

    /** ------------------------------------
     * Save evidence (filesystem + optional DB evidence table)
     * ------------------------------------*/
    private function save_evidence($id, $row) {
        if ( ! $id ) return;

        $folder = trailingslashit( self::DIR ) . intval($id);
        wp_mkdir_p( $folder );

        // Save JSON evidenc
        file_put_contents("$folder/evidence.json", wp_json_encode($row, JSON_PRETTY_PRINT));

        // Screenshot via URLBox/Urlbox/Urlbox-like service if configured
        $shot = false;
        $shot_path = "$folder/screenshot.png";
        if ( defined('SS_URLBOX_KEY') && SS_URLBOX_KEY ) {
            $shot = $this->screenshot($row['source']);
            if ($shot) {
                file_put_contents($shot_path, $shot);
            }
        }

        // Add evidence into DB via SS_Backlinks helper if available
        if ( class_exists('SS_Backlinks') && method_exists('SS_Backlinks', 'add_evidence') ) {
            try {
                SS_Backlinks::add_evidence($id, 'verification', $row);
            } catch (Throwable $e) {
                error_log("[SS Backlink Agent] add_evidence failed: " . $e->getMessage());
            }
        }
    }

    /** ------------------------------------
     * HTTP helpers
     * ------------------------------------*/
    private function get($url) {
        if ( empty($url) ) return null;
        $r = wp_remote_get($url, ['timeout' => 20, 'headers' => ['User-Agent' => 'SearchShifter-BacklinkAgent/1.0']]);
        if ( is_wp_error($r) ) {
            error_log('[SS Backlink Agent] wp_remote_get error for ' . $url . ' - ' . $r->get_error_message());
            return null;
        }
        return wp_remote_retrieve_body($r);
    }

    private function get_json($url) {
        $body = $this->get($url);
        if ( ! $body ) return null;
        $json = json_decode($body, true);
        if ( json_last_error() !== JSON_ERROR_NONE ) {
            return null;
        }
        return $json;
    }

    /** ------------------------------------
     * Screenshot via Urlbox (optional)
     * ------------------------------------*/
    private function screenshot($url) {
        if ( ! defined('SS_URLBOX_KEY') || ! SS_URLBOX_KEY ) return false;
        $api = "https://api.urlbox.io/v1/" . rawurlencode(SS_URLBOX_KEY) . "/png?url=" . rawurlencode($url) . "&full_page=true";
        $r = wp_remote_get($api, ['timeout' => 30]);
        if ( is_wp_error($r) ) {
            error_log('[SS Backlink Agent] screenshot urlbox error: ' . $r->get_error_message());
            return false;
        }
        return wp_remote_retrieve_body($r);
    }

} // end class

// Auto-init if setup doesn't call init() explicitly
SS_Backlink_Agent::init();

endif;
