<?php

namespace RecastPaywall\Frontend;

use RecastPaywall\Services\EntitlementService;

/**
 * Frontend content gating
 */
class ContentGating {
    /**
     * Entitlement service
     */
    private EntitlementService $entitlementService;

    /**
     * Paywall renderer
     */
    private PaywallRenderer $paywallRenderer;

    /**
     * Constructor
     */
    public function __construct(EntitlementService $entitlementService) {
        $this->entitlementService = $entitlementService;
        $this->paywallRenderer = new PaywallRenderer($entitlementService);
    }

    /**
     * Initialize hooks
     */
    public function init(): void {
        // Filter post content
        add_filter('the_content', [$this, 'filterContent'], 10, 1);
        
        // Filter excerpts on archive pages
        add_filter('the_excerpt', [$this, 'filterExcerpt'], 10, 1);
        add_filter('get_the_excerpt', [$this, 'filterExcerpt'], 10, 1);
        
        // Register shortcode
        add_shortcode('recast_paywall', [$this, 'renderShortcode']);
        
        // Add/send headers before any output is sent
        add_action('send_headers', [$this, 'addNoCacheHeaders']);
    }

    /**
     * Filter excerpts on archive/list pages
     * 
     * For paywalled posts that users don't have access to,
     * just return the excerpt without any content preview
     */
    public function filterExcerpt(string $excerpt): string {
        // Archive/list pages only show excerpt - no additional filtering needed
        // Content is already protected by filterContent() which only runs on singular pages
        return $excerpt;
    }

    /**
     * Filter post content
     */
    public function filterContent(string $content): string {
        static $inFilter = false;
        static $processedPosts = [];
        
        if ($inFilter) {
            return $content;
        }

        $postId = get_the_ID();
        
        // Prevent infinite loops by tracking processed posts
        if (isset($processedPosts[$postId])) {
            return $content;
        }
        
        // Set guard immediately to prevent any recursion
        $inFilter = true;
        $processedPosts[$postId] = true;
        
        // On archive/list pages, replace full content with excerpt for paywalled posts
        if (!is_singular()) {
            try {
                // Check if post is paywalled
                if ($this->entitlementService->isPostPaywalled($postId)) {
                    // Get excerpt directly from post object to avoid filter recursion
                    $post = get_post($postId);
                    $excerpt = $post && !empty($post->post_excerpt) 
                        ? $post->post_excerpt 
                        : wp_trim_words(strip_shortcodes($content), 55, '...');
                    return wpautop($excerpt);
                }
                return $content;
            } finally {
                $inFilter = false;
                unset($processedPosts[$postId]);
            }
        }
        
        try {
            // Respect gating mode: if set to 'block', skip post-level gating
            $mode = get_post_meta($postId, '_recast_gating_mode', true) ?: 'post';
            
            if ($mode === 'block') {
                // In block mode, we always need to check entitlement for block-level gating
                // This ensures the cache is populated for block filtering
                $userId = get_current_user_id();
                $this->entitlementService->isEntitled($postId, $userId);
                return $content;
            }

            // Check if post is paywalled
            if (!$this->entitlementService->isPostPaywalled($postId)) {
                return $content;
            }

            // Check if user is entitled
            $userId = get_current_user_id();
            $isEntitled = $this->entitlementService->isEntitled($postId, $userId);
            
            if ($isEntitled) {
                return $content;
            }

            // User is not entitled, show summary and paywall
            return $this->getGatedContent($postId, $content);
        } finally {
            $inFilter = false;
            unset($processedPosts[$postId]);
        }
    }

    /**
     * Get gated content (summary + paywall)
     */
    private function getGatedContent(int $postId, string $fullContent): string {
        return $this->paywallRenderer->renderPostPaywall($postId);
    }

    /**
     * Get post summary (uses excerpt)
     */
    public function getPostSummary(int $postId): string {
        // Delegate to PaywallRenderer which always uses excerpt
        return $this->paywallRenderer->getPostSummary($postId);
    }

    /**
     * Get paywall HTML
     */
    public function getPaywallHtml(int $postId): string {
        $settings = get_option('recast_paywall_settings', []);
        $brandId = $settings['brand_id'] ?? '';
        $sandbox = $settings['sandbox'] ?? false;
        
        if (empty($brandId)) {
            return '<p>' . esc_html__('Paywall not configured.', 'recast-paywall') . '</p>';
        }

        return sprintf(
            '<div class="recast-paywall-widget" 
                 data-brand-id="%s" 
                 data-sandbox="%s" 
                 data-post-id="%d">
                <div class="recast-paywall-loading">%s</div>
            </div>',
            esc_attr($brandId),
            $sandbox ? 'true' : 'false',
            $postId,
            esc_html__('Loading paywall...', 'recast-paywall')
        );
    }

    /**
     * Render shortcode
     */
    public function renderShortcode(array $atts, string $content = ''): string {
        $atts = shortcode_atts([
            'post_id' => get_the_ID(),
        ], $atts, 'recast_paywall');

        $postId = intval($atts['post_id']);
        
        if (!$postId) {
            return $content;
        }

        // Check if user is entitled
        $userId = get_current_user_id();
        if ($this->entitlementService->isEntitled($postId, $userId)) {
            return do_shortcode($content);
        }

        // User is not entitled, show paywall
        return sprintf(
            '<div class="recast-paywall-section" data-post-id="%d">
                <div class="recast-paywall-section-content">%s</div>
                <div class="recast-paywall-section-cta">%s</div>
            </div>',
            $postId,
            $this->getPostSummary($postId),
            $this->getPaywallHtml($postId)
        );
    }

    /**
     * Add no-cache headers for entitled users
     */
    public function addNoCacheHeaders(): void {
        if (headers_sent()) {
            return;
        }

        if (!is_singular()) {
            return;
        }

        $postId = get_queried_object_id();
        if (!$postId) {
            return;
        }

        if (!$this->entitlementService->isPostPaywalled($postId)) {
            return;
        }

        $userId = get_current_user_id();
        $isEntitled = $this->entitlementService->isEntitled($postId, $userId);

        // Only send no-cache headers if filter allows it
        if (apply_filters('recast_paywall_send_no_cache_headers', true, $postId, $isEntitled)) {
            if ($isEntitled) {
                // Entitled users should not be cached
                nocache_headers();
            } else {
                // Non-entitled users can be cached, but vary by user
                header('Vary: Cookie');
            }
        }
    }

    /**
     * Check if content should be gated (for theme developers)
     */
    public function shouldGateContent(int $postId): bool {
        if (!$this->entitlementService->isPostPaywalled($postId)) {
            return false;
        }

        $userId = get_current_user_id();
        return !$this->entitlementService->isEntitled($postId, $userId);
    }

    /**
     * Get entitlement status (for theme developers)
     */
    public function getEntitlementStatus(int $postId): array {
        $userId = get_current_user_id();
        $isEntitled = $this->entitlementService->isEntitled($postId, $userId);
        $isPaywalled = $this->entitlementService->isPostPaywalled($postId);

        return [
            'is_entitled' => $isEntitled,
            'is_paywalled' => $isPaywalled,
            'should_gate' => $isPaywalled && !$isEntitled,
            'user_id' => $userId,
        ];
    }
}
