<?php
namespace ShopyPress\Services;
if ( ! defined( 'ABSPATH' ) ) exit;

use ShopyPress\Helpers\ShopifyAuth;
use ShopyPress\Utils\OptionUtils;
use ShopyPress\Config\SyncConfig;

class ShopifyProductsService {
    private string $shop;
    private string $access_token;
    private static int $last_response_code = 0;
    private static ?array $last_throttle_status = null;

    public function __construct() {
        $this->shop = OptionUtils::getInstance()->getOption('shop_domain', '');
        $this->access_token = ShopifyAuth::getAccessToken($this->shop);
    }

    /**
     * Fetch all product IDs from a collection (cursor-based pagination)
     *
     * @param string $collection_id The Shopify collection ID
     * @param string|null $cursor Pagination cursor
     * @return array ['product_ids' => [...], 'has_next_page' => bool, 'end_cursor' => string|null]
     */
    public function fetchProductIdsFromCollection(string $collection_id, ?string $cursor = null): array {
        $query = $this->buildCollectionProductsQuery($collection_id, $cursor);
        $result = $this->executeGraphQL($query);

        if ($result === null) {
            return ['product_ids' => [], 'has_next_page' => false, 'end_cursor' => null];
        }

        $collection_data = $result['data']['collection'] ?? null;
        if (!$collection_data) {
            return ['product_ids' => [], 'has_next_page' => false, 'end_cursor' => null];
        }

        $products = $collection_data['products'] ?? [];
        $edges = $products['edges'] ?? [];
        $page_info = $products['pageInfo'] ?? [];

        $product_ids = array_map(function($edge) {
            return $edge['node']['id'];
        }, $edges);

        return [
            'product_ids' => $product_ids,
            'has_next_page' => $page_info['hasNextPage'] ?? false,
            'end_cursor' => $page_info['endCursor'] ?? null
        ];
    }

    /**
     * Fetch full product data by IDs (batch)
     *
     * @param array $product_ids Array of Shopify product IDs
     * @return array Array of full product objects
     */
    public function fetchProductsByIds(array $product_ids): array {
        if (empty($product_ids)) {
            return [];
        }

        $query = $this->buildProductsQuery($product_ids);
        $result = $this->executeGraphQL($query);

        if ($result === null) {
            return [];
        }

        $nodes = $result['data']['nodes'] ?? [];

        // Filter out null nodes (deleted products) and nodes without required fields
        return array_filter($nodes, function($node) {
            return $node !== null
                && isset($node['id'])
                && isset($node['status']);
        });
        
    }

    /**
     * Fetch shop-level data including currency settings
     *
     * @return array|null Shop data or null on failure
     */
    public function fetchShopData(): ?array {
        $query = $this->buildShopDataQuery();
        return $this->executeGraphQL($query);
    }

    /**
     * Build GraphQL query for shop data
     */
    private function buildShopDataQuery(): string {
        return '{
            shop {
                currencyCode
                currencyFormats {
                    moneyFormat
                    moneyInEmailsFormat
                    moneyWithCurrencyFormat
                    moneyWithCurrencyInEmailsFormat
                }
            }
        }';
    }

    /**
     * Build GraphQL query for fetching product IDs from a collection
     */
    private function buildCollectionProductsQuery(string $collection_id, ?string $cursor): string {
        $after_param = $cursor ? ', after: "' . addslashes($cursor) . '"' : '';
        $limit = SyncConfig::SHOPIFY_PRODUCTS_PER_PAGE;

        return '{
            collection(id: "' . addslashes($collection_id) . '") {
                products(first: ' . $limit . $after_param . ') {
                    edges {
                        node {
                            id
                        }
                    }
                    pageInfo {
                        hasNextPage
                        endCursor
                    }
                }
            }
        }';
    }

    /**
     * Build GraphQL query for fetching full product data
     */
    private function buildProductsQuery(array $product_ids): string {
        $ids_string = implode('","', array_map('addslashes', $product_ids));
        $variants_limit = SyncConfig::SHOPIFY_VARIANTS_PER_PRODUCT;
        $images_limit = SyncConfig::SHOPIFY_IMAGES_PER_PRODUCT;
        

        return '{
            nodes(ids: ["' . $ids_string . '"]) {
                ... on Product {
                    id
                    title
                    handle
                    description
                    descriptionHtml
                    productType
                    vendor
                    tags
                    status
                    totalInventory
                    updatedAt
                    priceRangeV2 {
                        minVariantPrice {
                            amount
                            currencyCode
                        }
                        maxVariantPrice {
                            amount
                            currencyCode
                        }
                    }
                    variants(first: ' . $variants_limit . ') {
                        edges {
                            node {
                                id
                                title
                                sku
                                price
                                compareAtPrice
                                inventoryQuantity
                                availableForSale
                                selectedOptions {
                                    name
                                    value
                                }
                                image {
                                    url
                                    altText
                                    width
                                    height
                                }
                                media(first: 10) {
                                    edges {
                                        node {
                                            mediaContentType
                                            ... on MediaImage {
                                                image {
                                                    url
                                                    altText
                                                    width
                                                    height
                                                }
                                            }
                                            ... on Video {
                                                sources {
                                                    url
                                                    mimeType
                                                }
                                                preview {
                                                    image {
                                                        url
                                                    }
                                                }
                                            }
                                            ... on ExternalVideo {
                                                embedUrl
                                                host
                                                preview {
                                                    image {
                                                        url
                                                    }
                                                }
                                            }
                                            ... on Model3d {
                                                sources {
                                                    url
                                                    mimeType
                                                }
                                                preview {
                                                    image {
                                                        url
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    images(first: ' . $images_limit . ') {
                        edges {
                            node {
                                url
                                altText
                            }
                        }
                    }
                    featuredMedia {
                        preview {
                            image {
                                url
                                altText
                            }
                        }
                        mediaContentType
                    }
                    media(first: ' . $images_limit . ') {
                        edges {
                            node {
                                mediaContentType
                                ... on MediaImage {
                                    image {
                                        url
                                        altText
                                        width
                                        height
                                    }
                                }
                                ... on Video {
                                    sources {
                                        url
                                        mimeType
                                    }
                                    preview {
                                        image {
                                            url
                                        }
                                    }
                                }
                                ... on ExternalVideo {
                                    embedUrl
                                    host
                                    preview {
                                        image {
                                            url
                                        }
                                    }
                                }
                                ... on Model3d {
                                    sources {
                                        url
                                        mimeType
                                    }
                                    preview {
                                        image {
                                            url
                                        }
                                    }
                                }
                            }
                        }
                    }
                    collections(first: 250) {
                        edges {
                            node {
                                id
                                title
                                handle
                                description
                                descriptionHtml
                                image {
                                    url
                                    altText
                                }
                                updatedAt
                            }
                        }
                    }
                }
            }
        }';
    }
    

    /**
     * Check rate limit and wait if necessary
     */
    private function handleRateLimit(?array $throttle_status = null): void {
        if ($throttle_status) {
            self::$last_throttle_status = $throttle_status;
        }

        if (!self::$last_throttle_status) {
            return;
        }

        $current = self::$last_throttle_status['currentlyAvailable'] ?? 2000;
        $maximum = self::$last_throttle_status['maximumAvailable'] ?? 2000;
        $restore_rate = self::$last_throttle_status['restoreRate'] ?? 100;

        // If available points are less than 20% of maximum, wait to restore
        $threshold = $maximum * 0.2;

        if ($current < $threshold) {
            // Calculate how long to wait to restore to 50% capacity
            $target_points = $maximum * 0.5;
            $points_needed = $target_points - $current;
            $wait_seconds = ceil($points_needed / $restore_rate);

            // Cap wait time at 10 seconds to avoid blocking too long
            $wait_seconds = min($wait_seconds, 10);

            if ($wait_seconds > 0) {
                sleep($wait_seconds);
            }
        }
    }

    /**
     * Execute GraphQL query with retry on 403
     */
    private function executeGraphQL(string $query): ?array {
        // Check rate limit before making request
        $this->handleRateLimit();
        $url = "https://{$this->shop}/admin/api/2025-10/graphql.json";

        $response = wp_remote_post($url, [
            'headers' => [
                'Content-Type' => 'application/json',
                'X-Shopify-Access-Token' => $this->access_token,
            ],
            'body' => json_encode(['query' => $query]),
            'timeout' => 30,
        ]);

        if (is_wp_error($response)) {
            return null;
        }

        $response_code = wp_remote_retrieve_response_code($response);
        self::$last_response_code = $response_code;

        // Handle 403 with token refresh and retry
        if ($response_code === 403) {
            ShopifyAuth::clearAccessToken();
            $this->access_token = ShopifyAuth::getAccessToken($this->shop);

            // Retry once
            $response = wp_remote_post($url, [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'X-Shopify-Access-Token' => $this->access_token,
                ],
                'body' => json_encode(['query' => $query]),
                'timeout' => 30,
            ]);

            if (is_wp_error($response)) {
                return null;
            }

            $response_code = wp_remote_retrieve_response_code($response);
            self::$last_response_code = $response_code;
        }

        if ($response_code !== 200) {
            return null;
        }

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

        if (isset($data['errors']) && !empty($data['errors'])) {
            return null;
        }

        // Extract and store throttle status for next request
        if (isset($data['extensions']['cost']['throttleStatus'])) {
            $this->handleRateLimit($data['extensions']['cost']['throttleStatus']);
        }

        return $data;
    }
}
