<?php
/**
 * Indexing Credits Backend Client (Week 27, updated Week 30).
 *
 * Talks to the backend service for:
 * - BoostCoin status (unified wallet)
 * - BoostCoin consumption (token-based, idempotent)
 *
 * Week 30: Credits are now unified BoostCoin with decimal precision.
 * PayPal purchase methods are deprecated - all purchases go through the unified flow.
 *
 * @package BoostBot
 */

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

class BoostBot_Indexing_Credits_Backend_Client {

    /**
     * Get configured backend base URL (no trailing slash).
     */
    public function get_base_url(): string {
        $base = (string) BoostBot_Settings::get( 'backend_base_url', '' );
        $base = trim( $base );
        return rtrim( $base, '/' );
    }

    /**
     * Ensure a site_id exists for this WP site (register if needed).
     *
     * @return string|WP_Error
     */
    public function ensure_site_id() {
        // Reuse the exact settings fields used by the unified credits backend client.
        $site_id  = trim( (string) BoostBot_Settings::get( 'backend_site_id', '' ) );
        $site_key = trim( (string) BoostBot_Settings::get( 'backend_site_api_key', '' ) );

        // Fast path: both site_id and site_api_key exist — fully configured.
        if ( '' !== $site_id && '' !== $site_key ) {
            return $site_id;
        }

        // ── Broken state detection: site_id exists but key is missing ──
        if ( '' !== $site_id && '' === $site_key ) {
            BoostBot_Logger::warning( '[Indexing] WARNING: backend_site_id is set (' . $site_id . ') but backend_site_api_key is missing. Attempting re-registration.' );
        }

        $home_url = home_url( '/' );
        $host     = wp_parse_url( $home_url, PHP_URL_HOST );
        if ( empty( $host ) ) {
            return new WP_Error( 'boostbot_backend_invalid_domain', 'Could not determine site domain.' );
        }

        $resp = $this->request(
            'POST',
            '/api/v1/sites/register',
            array(
                'domain'      => strtolower( $host ),
                'wp_site_url' => $home_url,
            )
        );

        if ( is_wp_error( $resp ) ) {
            return $resp;
        }

        if ( empty( $resp['site_id'] ) ) {
            return new WP_Error( 'boostbot_backend_register_failed', 'Registration failed (missing site_id).' );
        }

        BoostBot_Settings::set( 'backend_site_id', sanitize_text_field( $resp['site_id'] ) );

        if ( empty( $resp['site_api_key'] ) ) {
            BoostBot_Logger::error( '[Indexing] CRITICAL: Site ' . $resp['site_id'] . ' is already registered but no API key was returned.' );
            set_transient( 'boostbot_backend_key_missing', 1, DAY_IN_SECONDS );
            return new WP_Error(
                'boostbot_backend_missing_site_key',
                'Backend connection error: the site API key is missing and cannot be re-issued automatically. Please go to BoostBot Settings → Connection and click "Repair Connection", or contact support.'
            );
        }

        // Save the key and VERIFY it was persisted correctly.
        BoostBot_Settings::set( 'backend_site_api_key', sanitize_text_field( $resp['site_api_key'] ) );

        $verify = trim( (string) BoostBot_Settings::get( 'backend_site_api_key', '' ) );
        if ( '' === $verify ) {
            BoostBot_Logger::error( '[Indexing] CRITICAL: backend_site_api_key was saved but could not be read back.' );
            return new WP_Error(
                'boostbot_backend_key_save_failed',
                'Backend API key was received but could not be persisted. This may indicate a database or encryption issue.'
            );
        }

        return (string) $resp['site_id'];
    }

    /**
     * Fetch indexing credits status (backend provides a free starter allocation for new accounts).
     *
     * @param string $site_id
     * @return array|WP_Error
     */
    public function get_status( string $site_id ) {
        return $this->request( 'GET', '/api/v1/sites/' . rawurlencode( $site_id ) . '/indexing-credits/status' );
    }

    /**
     * Consume BoostCoin for indexing operations (idempotent, token-based).
     *
     * Week 30: Now uses token-based metering instead of chunk-based.
     *
     * @param string $site_id
     * @param array  $body {
     *     @type string $job_id         Job identifier
     *     @type int    $input_tokens   Number of input tokens consumed
     *     @type int    $output_tokens  Number of output tokens consumed (default 0)
     *     @type string $provider       AI provider (e.g., 'openai', 'google')
     *     @type string $model          Model name (e.g., 'text-embedding-3-small')
     *     @type string $idempotency_key Unique key for deduplication
     * }
     * @return array|WP_Error
     */
    public function consume( string $site_id, array $body ) {
        return $this->request(
            'POST',
            '/api/v1/sites/' . rawurlencode( $site_id ) . '/indexing-credits/consume',
            $body
        );
    }

    /**
     * Create PayPal order for indexing credits.
     *
     * @deprecated Week 30 - Indexing credits are now part of unified BoostCoin.
     *             Use the unified purchase flow on the Usage page instead.
     *
     * @param string $site_id
     * @param string $package_id
     * @param string $return_url
     * @param string $cancel_url
     * @return WP_Error Always returns deprecation error.
     */
    public function create_paypal_order( string $site_id, string $package_id, string $return_url, string $cancel_url ) {
        return new WP_Error(
            'boostbot_deprecated',
            __( 'Indexing credits are no longer sold separately. Please purchase BoostCoin from the Usage page.', 'boostbot' )
        );
    }

    /**
     * Capture PayPal order for indexing credits.
     *
     * @deprecated Week 30 - Indexing credits are now part of unified BoostCoin.
     *             Use the unified purchase flow on the Usage page instead.
     *
     * @param string $site_id
     * @param string $order_id
     * @return WP_Error Always returns deprecation error.
     */
    public function capture_paypal_order( string $site_id, string $order_id ) {
        return new WP_Error(
            'boostbot_deprecated',
            __( 'Indexing credits are no longer sold separately. Please purchase BoostCoin from the Usage page.', 'boostbot' )
        );
    }

    /**
     * Low-level HTTP request helper (mirrors Week 26 credits client).
     *
     * @param string $method
     * @param string $path
     * @param array|null $body
     * @return array|WP_Error
     */
    private function request( string $method, string $path, ?array $body = null ) {
        $base = $this->get_base_url();
        if ( empty( $base ) ) {
            return new WP_Error( 'boostbot_backend_not_configured', 'Backend not configured (missing backend_base_url).' );
        }

        $url = $base . $path;

        $raw_body = '';
        if ( null !== $body ) {
            $raw_body = wp_json_encode( $body );
            if ( false === $raw_body ) {
                return new WP_Error( 'boostbot_backend_invalid_json', 'Failed to encode request body.' );
            }
        }

        $headers = array(
            'Accept'       => 'application/json',
            'Content-Type' => 'application/json',
        );

        // Per-site backend API key (Authorization: Bearer <site_api_key>)
        $site_key = (string) BoostBot_Settings::get( 'backend_site_api_key', '' );
        $site_key = trim( $site_key );
        if ( ! empty( $site_key ) && '/api/v1/sites/register' !== $path ) {
            $headers['Authorization'] = 'Bearer ' . $site_key;
        }

        $args = array(
            'method'  => $method,
            'timeout' => 20,
            'headers' => $headers,
        );
        if ( null !== $body ) {
            $args['body'] = $raw_body;
        }

        $res = wp_remote_request( $url, $args );
        if ( is_wp_error( $res ) ) {
            return $res;
        }

        $status = (int) wp_remote_retrieve_response_code( $res );
        $text   = (string) wp_remote_retrieve_body( $res );

        $json = json_decode( $text, true );
        if ( ! is_array( $json ) ) {
            return new WP_Error( 'boostbot_backend_bad_response', 'Invalid backend response.' );
        }

        if ( isset( $json['success'] ) && false === $json['success'] ) {
            $msg = isset( $json['error']['message'] ) ? (string) $json['error']['message'] : 'Backend error';
            return new WP_Error( 'boostbot_backend_error', $msg, array( 'http_status' => $status, 'raw' => $json ) );
        }

        if ( isset( $json['data'] ) && is_array( $json['data'] ) ) {
            return $json['data'];
        }

        return $json;
    }
}

