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

use ShopyPress\Models\SyncState;
use ShopyPress\Config\SyncConfig;
use ShopyPress\Utils\OptionUtils;

class ProductSyncService {
    private float $start_time;
    private int $max_execution_time;
    private ProductRepository $product_repository;
    private ShopifyProductsService $shopify_service;

    public function __construct() {
        $this->start_time = microtime(true);
        $this->max_execution_time = SyncConfig::getMaxExecutionTime();
        $this->product_repository = new ProductRepository();
        $this->shopify_service = new ShopifyProductsService();
    }

    /**
     * Start or resume sync process
     *
     * @return array ['success' => bool, 'message' => string, 'state' => array]
     */
    public function startOrResumeSync(): array {
        try {
            $state = SyncState::load();

            if ($state === null) {
                // New sync process
                $state = new SyncState();
                $state->collection_ids = $this->getSelectedCollectionIds();
                $state->save();
            } elseif ($state->isCompleted()) {
                // Previous completed, start fresh
                SyncState::delete();
                $state = new SyncState();
                $state->collection_ids = $this->getSelectedCollectionIds();
                $state->save();
            } elseif ($state->hasError()) {
                // Don't auto-resume from error state
                return [
                    'success' => false,
                    'message' => 'Sync is in error state. Please reset to continue.',
                    'state' => $state->toArray()
                ];
            }

            // Execute phases
            if ($state->phase === SyncState::PHASE_SHOP_INIT) {
                $this->fetchShopData($state);
                $state->phase = SyncState::PHASE_COLLECTIONS;
                $state->save();
            }

            if ($state->phase === SyncState::PHASE_COLLECTIONS) {
                $this->fetchCollectionProducts($state);
            }

            if ($state->phase === SyncState::PHASE_PRODUCTS) {
                $completed = $this->syncProductsBatch($state);
                if ($completed) {
                    $state->phase = SyncState::PHASE_CLEANUP;
                    $state->save();
                }
            }

            if ($state->phase === SyncState::PHASE_CLEANUP) {
                $this->cleanupDeletedProducts($state);
                $this->cleanupEmptyCollections();
                $state->markCompleted();
                $state->save();
            }

            return [
                'success' => true,
                'message' => 'Sync progressing',
                'state' => $state->toArray()
            ];

        } catch (\Exception $e) {
            $state = SyncState::load() ?? new SyncState();
            $state->markError($e->getMessage());
            $state->save();

            return [
                'success' => false,
                'message' => $e->getMessage(),
                'state' => $state->toArray()
            ];
        }
    }

    /**
     * Phase 1: Fetch all product IDs from selected collections
     *
     * @param SyncState $state Current sync state
     */
    private function fetchCollectionProducts(SyncState $state): void {
        $all_product_ids = $state->product_ids;

        // Process collections starting from current index
        for ($i = $state->current_collection_index; $i < count($state->collection_ids); $i++) {
            $collection_id = $state->collection_ids[$i];
            $has_next_page = true;

            while ($has_next_page && !$this->isTimeUp()) {
                $result = $this->shopify_service->fetchProductIdsFromCollection(
                    $collection_id,
                    $state->cursor
                );

                $all_product_ids = array_merge($all_product_ids, $result['product_ids']);
                $has_next_page = $result['has_next_page'];
                $state->cursor = $result['end_cursor'];

                // Save state after each page
                $state->product_ids = array_values(array_unique($all_product_ids));
                $state->save();
            }

            if ($this->isTimeUp()) {
                // Time's up, save progress and exit
                $state->current_collection_index = $i;
                $state->save();
                return;
            }

            // Move to next collection
            $state->current_collection_index = $i + 1;
            $state->cursor = null; // Reset cursor for next collection
            $state->save();
        }

        // All collections processed
        $state->product_ids = array_values(array_unique($all_product_ids));
        $state->total_products = count($state->product_ids);
        $state->phase = SyncState::PHASE_PRODUCTS;
        $state->offset = 0;
        $state->save();
    }

    /**
     * Phase 2: Sync products in batches
     *
     * @param SyncState $state Current sync state
     * @return bool True if all products synced, false if more work to do
     */
    private function syncProductsBatch(SyncState $state): bool {
        while (!$this->isTimeUp()) {
            // Get next batch of product IDs
            $batch_ids = array_slice(
                $state->product_ids,
                $state->offset,
                $state->batch_size
            );

            if (empty($batch_ids)) {
                // All products synced
                return true;
            }

            // Fetch full product data from Shopify
            $products = $this->shopify_service->fetchProductsByIds($batch_ids);

            // Create/update each product in WordPress
            foreach ($products as $product) {
                try {
                    $this->product_repository->createOrUpdate($product);
                    $state->total_processed++;
                } catch (\Exception $e) {
                    $state->addError('Product ' . ($product['title'] ?? 'unknown') . ': ' . $e->getMessage());
                }
            }

            // Update offset
            $state->offset += count($batch_ids);
            $state->save();
        }

        // More work to do, time's up
        return false;
    }

    /**
     * Phase 3: Cleanup - delete products that no longer exist in Shopify
     *
     * @param SyncState $state Current sync state
     */
    private function cleanupDeletedProducts(SyncState $state): void {
        $wp_shopify_ids = $this->product_repository->getAllShopifyProductIds();
        $shopify_ids = $state->product_ids;

        // Find products in WordPress but not in Shopify
        $to_delete = array_diff($wp_shopify_ids, $shopify_ids);

        foreach ($to_delete as $shopify_id) {
            $post_id = $this->product_repository->findByShopifyId($shopify_id);
            if ($post_id) {
                $this->product_repository->forceDelete($post_id);
            }
        }
    }

    /**
     * Cleanup empty collection taxonomy terms
     */
    private function cleanupEmptyCollections(): void {
        $collection_service = new CollectionTaxonomyService();
        $collection_service->cleanupEmptyCollections();
    }

    /**
     * Phase 0: Fetch shop-level data (currency settings)
     *
     * @param SyncState $state Current sync state
     */
    private function fetchShopData(SyncState $state): void {
        $shop_data = $this->shopify_service->fetchShopData();

        if ($shop_data === null) {
            // Log warning but don't fail the sync
            $state->addError('Warning: Failed to fetch shop currency data');
            return;
        }

        $shop = $shop_data['data']['shop'] ?? null;
        if (!$shop) {
            $state->addError('Warning: Shop data not found in response');
            return;
        }

        // Store currency settings
        OptionUtils::getInstance()->setOption('shop_currency_settings', [
            'currency_code' => $shop['currencyCode'] ?? 'USD',
            'currency_formats' => [
                'money_format' => $shop['currencyFormats']['moneyFormat'] ?? '',
                'money_in_emails_format' => $shop['currencyFormats']['moneyInEmailsFormat'] ?? '',
                'money_with_currency_format' => $shop['currencyFormats']['moneyWithCurrencyFormat'] ?? '',
                'money_with_currency_in_emails_format' => $shop['currencyFormats']['moneyWithCurrencyInEmailsFormat'] ?? ''
            ],
            'last_updated' => time()
        ]);
    }

    /**
     * Check if execution time limit is reached
     *
     * @return bool True if time is up
     */
    private function isTimeUp(): bool {
        $elapsed = microtime(true) - $this->start_time;
        return $elapsed >= $this->max_execution_time;
    }

    /**
     * Get selected collection IDs from options
     *
     * @return array Array of collection IDs
     */
    private function getSelectedCollectionIds(): array {
        $selected = OptionUtils::getInstance()->getOption('selected_collections', []);
        return array_keys($selected);
    }
}
