<?php

namespace AC_SYNC\Includes\Classes\Async\Handlers;

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

use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Handler_Interface;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Result as JobResult;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Queue as JobQueue;
use AC_SYNC\Includes\Classes\Product\Action_Wear_Product as Product;
use AC_SYNC\Includes\Classes\Api\Action_Wear_Api_Exception as ApiException;
use AC_SYNC\Includes\Classes\Sync\Action_Wear_Sync_Cache as SyncCache;
use AC_SYNC\Includes\Classes\Logger\Action_Wear_Log as Log;

class Action_Wear_Product_Import_Handler implements Action_Wear_Job_Handler_Interface
{
    public function handle(object $job, array $payload): JobResult
    {
        $sku = $payload['sku'] ?? null;
        if (!$sku) {
            return JobResult::fail('No SKU in payload');
        }

        // Warm caches on first import (transient handles dedup — only fetches if missing)
        SyncCache::warmPriceCache();
        SyncCache::warmQuantityCache();

        // Fetch product data from API
        try {
            $products = Product::getRemoteProductsListino([$sku]);
        } catch (ApiException $e) {
            return JobResult::retry(300, "API error for SKU {$sku}: " . $e->getMessage());
        }

        $product = $products->{$sku} ?? null;

        if (!$product) {
            Log::write("ProductImportHandler: SKU {$sku} not found in API response", Log::ERROR, Log::CONTEXT_CRONJOB);
            return JobResult::fail("SKU {$sku} not found in API");
        }

        // Create/update product with price/quantity from cache
        Product::createOrUpdateWcProduct($product);
        self::applyPricesAndQuantities($product);

        Log::write("ProductImportHandler: Imported SKU {$sku} (with prices/quantities)", Log::INFO, Log::CONTEXT_CRONJOB);

        // Check if this is the last import job — cleanup cache
        $followUp = [];
        if (!JobQueue::hasPending('product_import', (int) $job->id)) {
            SyncCache::flush();
            Log::write("ProductImportHandler: Last import done, cache flushed", Log::INFO, Log::CONTEXT_CRONJOB);
        }

        return JobResult::success($followUp);
    }

    /**
     * Apply cached prices and quantities to all variations of the imported product.
     */
    private static function applyPricesAndQuantities($product): void
    {
        global $wpdb;

        $simpleProducts = (array) $product->simple_products;
        if (empty($simpleProducts)) return;

        $skus = array_map(function ($s) { return $s->sku; }, $simpleProducts);
        $skus = array_unique($skus);

        if (empty($skus)) return;

        // Batch lookup: SKU -> post_id
        $placeholders = implode(',', array_fill(0, count($skus), '%s'));
        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT pm.meta_value AS sku, pm.post_id
                FROM {$wpdb->postmeta} pm
                INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
                WHERE pm.meta_key = '_sku'
                AND p.post_type = 'product_variation'
                AND pm.meta_value IN ($placeholders)",
                ...$skus
            )
        );

        $skuToPostId = [];
        foreach ($results as $row) {
            $skuToPostId[$row->sku] = (int) $row->post_id;
        }

        if (empty($skuToPostId)) return;

        // Batch pre-fetch brand_id and cat_ids for price recharge
        $postIds = array_values($skuToPostId);
        $idPlaceholders = implode(',', array_fill(0, count($postIds), '%d'));
        $metaResults = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT post_id, meta_key, meta_value
                FROM {$wpdb->postmeta}
                WHERE post_id IN ($idPlaceholders)
                AND meta_key IN ('brand_id', 'cat_ids')",
                ...$postIds
            )
        );
        $metaMap = [];
        foreach ($metaResults as $meta) {
            $metaMap[$meta->post_id][$meta->meta_key] = $meta->meta_value;
        }

        $updatedParentIds = [];

        foreach ($skuToPostId as $sku => $postId) {
            // Apply price from cache
            $priceData = SyncCache::getPrice($sku);
            if ($priceData) {
                $basePrice = $priceData['base_price'];
                $brandId = (int) ($metaMap[$postId]['brand_id'] ?? 0);
                $catIds = json_decode($metaMap[$postId]['cat_ids'] ?? '[]', true) ?? [];

                $priceRecharger = new \AC_SYNC\Includes\Classes\Price\Action_Wear_Price_Recharger($basePrice);
                $finalPrice = $priceRecharger->getPrice($brandId, $catIds);

                if ((float) $finalPrice > 0) {
                    $formattedPrice = wc_format_decimal($finalPrice);
                    update_post_meta($postId, '_regular_price', $formattedPrice);
                    update_post_meta($postId, '_price', $formattedPrice);
                    update_post_meta($postId, 'original_base_price', $basePrice);
                    delete_post_meta($postId, '_needs_price_sync');

                    $wpdb->update(
                        $wpdb->prefix . 'wc_product_meta_lookup',
                        ['min_price' => $formattedPrice, 'max_price' => $formattedPrice],
                        ['product_id' => $postId],
                        ['%s', '%s'],
                        ['%d']
                    );
                }
            }

            // Apply quantity from cache
            $qtyData = SyncCache::getQuantity($sku);
            if ($qtyData) {
                $available = (float) ($qtyData['available'] ?? 0);
                update_post_meta($postId, '_manage_stock', 'yes');
                update_post_meta($postId, '_stock', $available);
                update_post_meta($postId, '_stock_status', $available > 0 ? 'instock' : 'outofstock');

                if (isset($qtyData['total_arrivals'])) {
                    update_post_meta($postId, 'total_arrivals', (float) $qtyData['total_arrivals']);
                }
                if (isset($qtyData['supplier'])) {
                    update_post_meta($postId, 'quantity_supplier', (float) $qtyData['supplier']);
                }
                delete_post_meta($postId, '_needs_quantity_sync');

                $wpdb->update(
                    $wpdb->prefix . 'wc_product_meta_lookup',
                    [
                        'stock_quantity' => $available,
                        'stock_status'   => $available > 0 ? 'instock' : 'outofstock',
                    ],
                    ['product_id' => $postId],
                    ['%f', '%s'],
                    ['%d']
                );
            }

            wc_delete_product_transients($postId);

            $parentId = wp_get_post_parent_id($postId);
            if ($parentId) {
                $updatedParentIds[$parentId] = true;
            }
        }

        // Sync parent products
        foreach (array_keys($updatedParentIds) as $parentId) {
            if (function_exists('wc_update_product_lookup_tables_column')) {
                wc_update_product_lookup_tables_column($parentId, 'min_max_price');
            }
            // Sync parent stock status
            $parentProduct = wc_get_product($parentId);
            if ($parentProduct && $parentProduct->is_type('variable')) {
                $children = $parentProduct->get_children();
                $hasInStock = false;
                foreach ($children as $childId) {
                    if (get_post_meta($childId, '_stock_status', true) === 'instock') {
                        $hasInStock = true;
                        break;
                    }
                }
                $parentProduct->set_stock_status($hasInStock ? 'instock' : 'outofstock');
                $parentProduct->save();
            }
            wc_delete_product_transients($parentId);
        }
    }
}
