<?php
namespace Consolety;

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

/**
 * API class for Hub communication
 */
class Api {

    private $token;
    private $hub_url;

    public function __construct() {
        $this->hub_url = \CONSOLETY_HUB_URL;
        $this->token = get_option('consolety_trust_token', '');
    }

    /**
     * Set API token
     */
    public function setToken($token) {
        $this->clearHealthCache();  // Clear old token's cache
        $this->token = $token;
    }

    /**
     * Get current token
     */
    public function getToken() {
        return $this->token;
    }

    /**
     * Check if connected (token present - fast, no side effects)
     */
    public function isConnected() {
        return !empty($this->token);
    }

    /**
     * Validate if connection is actually healthy (API call, cached)
     * Call this on admin pages where connection matters
     */
    public function validateConnectionHealth() {
        if (!$this->isConnected()) {
            return false;
        }

        // Cache per token hash (5 min)
        $tokenHash = substr(md5($this->token), 0, 8);
        $cacheKey = 'consolety_health_' . $tokenHash;
        $cached = get_transient($cacheKey);

        if ($cached !== false) {
            return $cached === 'valid';
        }

        // Lightweight health check
        $response = $this->get('/site/status');
        $httpCode = $response['http_code'] ?? 200;
        $isValid = !empty($response['success']);

        // ALLEEN cachen en flag zetten bij definitieve uitkomsten
        if ($isValid) {
            set_transient($cacheKey, 'valid', 5 * MINUTE_IN_SECONDS);
            delete_option('consolety_connection_invalid');
            return true;
        }

        if ($httpCode === 401) {
            // Token definitief invalid
            set_transient($cacheKey, 'invalid', 5 * MINUTE_IN_SECONDS);
            update_option('consolety_connection_invalid', 1);
            return false;
        }

        // 500/timeout: geen cache poisoning, return true (assume valid)
        return true;
    }

    /**
     * Clear health cache for current token
     * Call on token set/change/disconnect
     */
    public function clearHealthCache() {
        if (!empty($this->token)) {
            $tokenHash = substr(md5($this->token), 0, 8);
            delete_transient('consolety_health_' . $tokenHash);
        }
        delete_option('consolety_connection_invalid');
    }

    /**
     * Make GET request to Hub API
     */
    public function get($endpoint, $params = []) {
        $url = $this->hub_url . '/api/v1' . $endpoint;

        if (!empty($params)) {
            $url .= '?' . http_build_query($params);
        }

        return $this->request('GET', $url);
    }

    /**
     * Make POST request to Hub API
     */
    public function post($endpoint, $data = [], $options = []) {
        return $this->request('POST', $this->hub_url . '/api/v1' . $endpoint, $data, $options);
    }

    /**
     * Make PUT request to Hub API
     */
    public function put($endpoint, $data = []) {
        return $this->request('PUT', $this->hub_url . '/api/v1' . $endpoint, $data);
    }

    /**
     * Make DELETE request to Hub API
     */
    public function delete($endpoint) {
        return $this->request('DELETE', $this->hub_url . '/api/v1' . $endpoint);
    }

    /**
     * Core HTTP request method
     */
    private function request($method, $url, $data = [], $options = []) {
        $args = [
            'method' => $method,
            'timeout' => $options['timeout'] ?? 45,
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
                'X-Site-URL' => home_url(),
                'X-Plugin-Version' => CONSOLETY_VERSION,
            ],
        ];

        // Add auth token
        if (!empty($this->token)) {
            $args['headers']['Authorization'] = 'Bearer ' . $this->token;
        }

        // Add body for POST/PUT requests
        if (in_array($method, ['POST', 'PUT']) && !empty($data)) {
            $args['body'] = wp_json_encode($data);
        }

        $response = wp_remote_request($url, $args);

        if (is_wp_error($response)) {
            set_transient('consolety_last_api_error', 'Request failed: ' . $response->get_error_message(), HOUR_IN_SECONDS);
            return [
                'success' => false,
                'error' => [
                    'code' => 'REQUEST_FAILED',
                    'message' => $response->get_error_message(),
                ],
            ];
        }

        $body = wp_remote_retrieve_body($response);
        $decoded = json_decode($body, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            return [
                'success' => false,
                'error' => [
                    'code' => 'INVALID_RESPONSE',
                    'message' => 'Invalid JSON response from server',
                ],
            ];
        }

        // Check HTTP status code for error responses
        // Hub API returns proper error codes (409 ALREADY_CONNECTED, 402 INSUFFICIENT_CREDITS, etc.)
        $httpCode = wp_remote_retrieve_response_code($response);
        if ($httpCode >= 400) {
            // Ensure success is false for error responses
            if (!isset($decoded['success'])) {
                $decoded['success'] = false;
            }
            $errorMsg = $decoded['error']['message'] ?? ($decoded['message'] ?? 'Unknown error');
            set_transient('consolety_last_api_error', 'HTTP ' . $httpCode . ': ' . $errorMsg, HOUR_IN_SECONDS);
        }

        // Clear stale error on successful response so Diagnostics stays accurate
        if ($httpCode < 400) {
            delete_transient('consolety_last_api_error');
        }

        // Include HTTP code in response for health checks
        $decoded['http_code'] = $httpCode;

        return $decoded;
    }

    // ==========================================
    // Site Management
    // ==========================================

    /**
     * Register site with Hub
     */
    public function registerSite() {
        return $this->post('/site/register');
    }

    /**
     * Fetch site status from Hub
     */
    public function fetchSiteStatus() {
        return $this->get('/site/status');
    }

    /**
     * Send heartbeat to Hub
     */
    public function sendHeartbeat() {
        return $this->post('/site/heartbeat', [
            'webhook_url' => rest_url('consolety/v1/webhook'),
            'plugin_version' => CONSOLETY_VERSION,
        ]);
    }

    /**
     * Refresh GSC metrics
     */
    public function refreshMetrics($options = []) {
        return $this->post('/site/refresh-metrics', [], $options);
    }

    /**
     * Get OAuth URL for connecting
     *
     * Generates a one-time nonce stored in a transient (10 min expiry).
     * The Hub will echo this nonce back in the callback URL so we can verify
     * the callback originated from our own OAuth initiation.
     */
    public function getOAuthUrl() {
        $return_url = admin_url('admin.php?page=consolety');

        // Generate one-time nonce for callback verification
        $oauthNonce = wp_generate_uuid4();
        set_transient('consolety_oauth_nonce', $oauthNonce, 1800); // 30 minutes

        return $this->hub_url . '/auth/google/redirect?' . http_build_query([
            'site_url' => home_url(),
            'return_url' => $return_url,
            'oauth_nonce' => $oauthNonce,
        ]);
    }

    /**
     * Disconnect from Hub
     */
    public function disconnect() {
        // Clear health cache BEFORE clearing token
        $this->clearHealthCache();

        // Notify Hub
        $this->post('/site/disconnect');

        // Clear local options
        delete_option('consolety_trust_token');
        delete_option('consolety_api_token');  // Legacy key - prevent re-migration
        delete_option('consolety_site_id');
        delete_option('consolety_tier');
        delete_option('consolety_metrics');
        delete_option('consolety_webhook_secret');
        delete_option('consolety_site_info');

        $this->token = '';
    }

    // ==========================================
    // Network / Connections
    // ==========================================

    /**
     * Get available network partners
     */
    public function getNetworkPartners($params = []) {
        return $this->get('/network/partners', $params);
    }

    /**
     * Get a public, read-only preview of the live network.
     * Works WITHOUT a trust token (used on the pre-connection onboarding screen).
     */
    public function getNetworkShowcase() {
        return $this->get('/network/showcase');
    }

    /**
     * Send connection request to a partner
     */
    public function sendConnectionRequest($targetSiteId, $message = '', $connectionType = 'guest_post', $idempotencyKey = '') {
        $data = [
            'target_site_id' => $targetSiteId,
            'connection_type' => $connectionType,
            'message' => $message,
        ];

        if (!empty($idempotencyKey)) {
            $data['idempotency_key'] = $idempotencyKey;
        }

        return $this->post('/connections', $data);
    }

    /**
     * Update site profile (category, language, bio)
     */
    public function updateSiteProfile($data) {
        return $this->post('/site/profile', $data);
    }

    /**
     * Get site profile
     */
    public function getSiteProfile() {
        return $this->get('/site/profile');
    }

    /**
     * Get recent activity feed for the dashboard
     */
    public function getActivity() {
        return $this->get('/site/activity');
    }

    /**
     * Respond to a connection request (accept/reject)
     */
    public function respondToConnection($connectionId, $action) {
        return $this->put('/connections/' . $connectionId, [
            'action' => $action,
        ]);
    }

    /**
     * Cancel a connection request or disconnect
     */
    public function cancelConnection($connectionId) {
        return $this->delete('/connections/' . $connectionId);
    }

    /**
     * Get all connections (sent, received, connected)
     */
    public function getConnections() {
        return $this->get('/connections');
    }

    // ==========================================
    // Guest Posts
    // ==========================================

    /**
     * Get all guest posts (my submissions + pending review + received)
     */
    public function getGuestPosts() {
        return $this->get('/guest-posts');
    }

    /**
     * Get available partners for guest post submission
     */
    public function getGuestPostPartners() {
        return $this->get('/guest-posts/partners');
    }

    /**
     * Get single guest post details
     */
    public function getGuestPost($postId) {
        return $this->get('/guest-posts/' . $postId);
    }

    /**
     * Create new guest post
     */
    public function createGuestPost($data) {
        return $this->post('/guest-posts', $data);
    }

    /**
     * Update existing guest post
     */
    public function updateGuestPost($postId, $data) {
        return $this->put('/guest-posts/' . $postId, $data);
    }

    /**
     * Approve guest post
     */
    public function approveGuestPost($postId, $data) {
        return $this->post('/guest-posts/' . $postId . '/approve', $data);
    }

    /**
     * Reject guest post
     */
    public function rejectGuestPost($postId, $reason) {
        return $this->post('/guest-posts/' . $postId . '/reject', [
            'reason' => $reason,
        ]);
    }

    /**
     * Request revision on guest post
     */
    public function requestRevision($postId, $feedback) {
        return $this->post('/guest-posts/' . $postId . '/request-revision', [
            'feedback' => $feedback,
        ]);
    }

    /**
     * Withdraw guest post submission
     */
    public function withdrawGuestPost($postId) {
        return $this->post('/guest-posts/' . $postId . '/withdraw');
    }

    // ==========================================
    // Points / Credits
    // ==========================================

    /**
     * Get current points balance
     */
    public function getPointsBalance() {
        return $this->get('/points/balance');
    }

    /**
     * Get points transaction history
     */
    public function getPointsHistory($params = []) {
        return $this->get('/points/transactions', $params);
    }

    /**
     * Claim daily points reward
     */
    public function claimDailyPoints() {
        return $this->post('/points/claim-daily');
    }

    // ==========================================
    // Badge Counts
    // ==========================================

    /**
     * Get dashboard badge counts for admin menu notifications
     */
    public function getBadgeCounts() {
        return $this->get('/badge-counts');
    }

    // ==========================================
    // Categories
    // ==========================================

    /**
     * Get all available categories
     */
    public function getCategories() {
        return $this->get('/categories');
    }

    // ==========================================
    // Link Monitoring (Anti-Fraud)
    // ==========================================

    /**
     * Report link monitoring results to Hub
     */
    public function reportLinkStatus($guestPostId, $status, $details = []) {
        return $this->post('/monitoring/report', [
            'guest_post_id' => $guestPostId,
            'status' => $status,
            'details' => $details,
        ]);
    }

    /**
     * Get posts that need link monitoring
     */
    public function getPostsToMonitor() {
        return $this->get('/monitoring/posts');
    }

    // ==========================================
    // Campaigns (Article Marketplace)
    // ==========================================

    /**
     * Get all open campaigns (excluding own)
     */
    public function getCampaigns() {
        return $this->get('/campaigns');
    }

    /**
     * Get my campaigns (as creator)
     */
    public function getMyCampaigns() {
        return $this->get('/campaigns/my');
    }

    /**
     * Get my claims (as publisher)
     */
    public function getMyClaims() {
        return $this->get('/campaigns/claims');
    }

    /**
     * Get single campaign details
     */
    public function getCampaign($campaignId) {
        return $this->get('/campaigns/' . $campaignId);
    }

    /**
     * Create new campaign (Free: max 2 active, Pro: unlimited)
     */
    public function createCampaign($data) {
        return $this->post('/campaigns', $data);
    }

    /**
     * Claim a campaign
     */
    public function claimCampaign($campaignId, $pitch = '', $idempotencyKey = '') {
        $data = ['pitch' => $pitch];
        if ($idempotencyKey) {
            $data['idempotency_key'] = $idempotencyKey;
        }
        return $this->post('/campaigns/' . $campaignId . '/claim', $data);
    }

    /**
     * Accept a claim (as campaign owner)
     */
    public function acceptClaim($campaignId, $claimId) {
        return $this->post('/campaigns/' . $campaignId . '/claims/' . $claimId . '/accept');
    }

    /**
     * Reject a claim (as campaign owner)
     */
    public function rejectClaim($campaignId, $claimId) {
        return $this->post('/campaigns/' . $campaignId . '/claims/' . $claimId . '/reject');
    }

    /**
     * Mark claim as published (after WP post creation)
     */
    public function markClaimPublished($campaignId, $claimId, $wpPostId, $publishedUrl) {
        return $this->post('/campaigns/' . $campaignId . '/claims/' . $claimId . '/published', [
            'wp_post_id' => $wpPostId,
            'published_url' => $publishedUrl,
        ]);
    }

    /**
     * Withdraw a campaign (as owner)
     */
    public function withdrawCampaign($campaignId) {
        return $this->post('/campaigns/' . $campaignId . '/withdraw');
    }

    /**
     * Dismiss a guest post (hide from UI)
     */
    public function dismissGuestPost($postId) {
        return $this->post('/guest-posts/' . $postId . '/dismiss');
    }

    /**
     * Dismiss a campaign (hide from UI)
     */
    public function dismissCampaign($campaignId) {
        return $this->post('/campaigns/' . $campaignId . '/dismiss');
    }

    /**
     * Dismiss a campaign claim (hide from UI)
     */
    public function dismissClaim($claimId) {
        return $this->post('/campaigns/claims/' . $claimId . '/dismiss');
    }
}
