<?php

namespace App\Http\Controllers;

use App\Actions\ListShopifyCollectionsAction;
use App\Actions\UpdateShopifyCollectionCostPrice;
use App\Actions\UpdateShopifyCollectionCostPriceFrontGold;
use App\Jobs\UpdateCollectionCostPriceJob;
use App\Models\CollectionCostConfiguration;
use App\Models\CollectionCostPriceLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;

class ShopifyCostPriceController extends Controller
{
    //
    public function listProducts()
    {

        $data = (new ListShopifyCollectionsAction())();


        return Inertia::render('cost-price', ["collections" => $data["collections"], "total" => $data["total"]]);
    }

    /**
     * Get products from a collection
     */
    public function getCollectionProducts(Request $request)
    {
        $collectionId = $request->query('collection_id');

        if (!$collectionId) {
            return response()->json([
                'status' => 400,
                'message' => 'Collection ID is required',
                'data' => null,
            ], 400);
        }

        try {
            $action = new UpdateShopifyCollectionCostPrice();
            $shopifyData = $action->fetchCollectionData($collectionId);

            // Extract products with id and title only
            $products = array_map(function ($item) {
                return [
                    'id' => $item['node']['id'],
                    'title' => $item['node']['title']
                ];
            }, $shopifyData['products']);

            return response()->json([
                'status' => 200,
                'message' => 'Products retrieved successfully',
                'data' => $products,
            ], 200);
        } catch (\Throwable $th) {
            Log::error("Failed to get collection products", [
                'collection_id' => $collectionId,
                'error' => $th->getMessage()
            ]);

            return response()->json([
                'status' => 500,
                'message' => 'Failed to get products: ' . $th->getMessage(),
                'data' => null,
            ], 500);
        }
    }

    public function updatePriceFrontGold(Request $request)
    {
        $result = (new UpdateShopifyCollectionCostPriceFrontGold())($request);
        return response()->json($result);
    }

    public function updatePrice(Request $request)
    {
        $demo = $request->input('demo');

        // If demo mode, process synchronously (current behavior)
        if ($demo) {
            $result = (new UpdateShopifyCollectionCostPrice())($request);

            return response()->json([
                'status' => 200,
                'message' => 'Update collection result',
                'data' => $result,
            ], 200);
        }

        // For non-demo mode, process asynchronously
        try {
            $collectionId = $request->input('collection_id');
            $selectedProductIds = $request->input('selected_product_ids'); // Array of product IDs or null
            $onlyDraft = $request->input('only_draft', false);

            // Get data from Shopify using Action
            $action = new UpdateShopifyCollectionCostPrice();
            $shopifyData = $action->fetchCollectionData($collectionId);

            // Filter products if specific products are selected
            if ($selectedProductIds && is_array($selectedProductIds) && count($selectedProductIds) > 0) {
                $shopifyData['products'] = array_filter($shopifyData['products'], function ($item) use ($selectedProductIds) {
                    return in_array($item['node']['id'], $selectedProductIds);
                });
                // Re-index array after filtering
                $shopifyData['products'] = array_values($shopifyData['products']);
            }

            // Filter products by status (only draft) if only_draft is true
            if ($onlyDraft) {
                $shopifyData['products'] = array_filter($shopifyData['products'], function ($item) {
                    $status = $item['node']['status'] ?? null;
                    return strtoupper($status) === 'DRAFT';
                });
                // Re-index array after filtering
                $shopifyData['products'] = array_values($shopifyData['products']);
            }

            // Calculate total variants
            $totalVariants = $action->calculateTotalVariants(
                $shopifyData['products'],
                $shopifyData['excluded_product_ids']
            );


            // Generate progress ID
            $progressId = 'cost_price_progress_' . uniqid();

            // CRITICAL: Store the initial total in a separate key that will NEVER change
            // This ensures the total remains constant throughout the entire process
            $initialTotalKey = "{$progressId}_initial_total";
            Cache::put($initialTotalKey, $totalVariants, 3600); // Store for 1 hour

            // Initialize cache with total real
            Cache::put($progressId, [
                'total' => $totalVariants,
                'processed' => 0,
                'errors' => 0,
                'status' => 'processing',
                'current_variant' => 'Initializing...',
            ], 3600); // 1 hour TTL

            // Dispatch job with all data

            try {
                $job = new UpdateCollectionCostPriceJob(
                    $request->all(),
                    $shopifyData['products'],
                    $shopifyData['title'],
                    $shopifyData['excluded_product_ids'],
                    $progressId
                );

                dispatch($job);
            } catch (\Throwable $dispatchError) {
                Log::error("Failed to dispatch job", [
                    'progress_id' => $progressId,
                    'error' => $dispatchError->getMessage(),
                    'trace' => $dispatchError->getTraceAsString(),
                ]);
                throw $dispatchError;
            }

            // Return 202 Accepted with progress ID
            return response()->json([
                'status' => 202,
                'message' => 'Processing started',
                'data' => [
                    'progress_id' => $progressId
                ],
            ], 202);
        } catch (\Throwable $th) {
            Log::error("Failed to start cost price update", [
                'error' => $th->getMessage(),
                'trace' => $th->getTraceAsString()
            ]);

            return response()->json([
                'status' => 500,
                'message' => 'Failed to start processing: ' . $th->getMessage(),
                'data' => null,
            ], 500);
        }
    }

    /**
     * Get saved configuration for a collection
     */
    public function getConfiguration(Request $request)
    {
        $collectionId = $request->query('collection_id') ?? $request->input('collection_id');

        if (!$collectionId) {
            return response()->json([
                'status' => 400,
                'message' => 'Collection ID is required',
                'data' => null,
            ], 400);
        }

        $configuration = CollectionCostConfiguration::getForCollection($collectionId);

        if (!$configuration) {
            return response()->json([
                'status' => 404,
                'message' => 'No configuration found for this collection',
                'data' => null,
            ], 404);
        }

        return response()->json([
            'status' => 200,
            'message' => 'Configuration loaded successfully',
            'data' => [
                'profit_ranges' => $configuration->profit_ranges ?? [],
                'expenses' => $configuration->expenses ?? [],
                'rounding_option' => $configuration->rounding_option ?? 'default',
            ],
        ], 200);
    }

    /**
     * Get latest cost price operation logs
     */
    public function getLatestLogs(Request $request)
    {
        $limit = $request->query('limit', 5);

        $logs = CollectionCostPriceLog::getLatest($limit);

        return response()->json([
            'status' => 200,
            'message' => 'Logs retrieved successfully',
            'data' => $logs->map(function ($log) {
                return [
                    'id' => $log->id,
                    'collection_title' => $log->collection_title,
                    'status' => $log->status,
                    'executed_at' => $log->executed_at->format('Y-m-d H:i:s'),
                    'executed_at_human' => $log->executed_at->diffForHumans(),
                    'total_variants' => $log->total_variants,
                    'updated_variants' => $log->updated_variants,
                    'errors' => $log->errors,
                    'demo_mode' => $log->demo_mode,
                ];
            }),
        ], 200);
    }

    /**
     * Get progress for a cost price update operation
     */
    public function getProgress(Request $request)
    {
        $progressId = $request->query('progress_id');

        if (!$progressId) {
            return response()->json([
                'status' => 400,
                'message' => 'Progress ID is required',
                'data' => null,
            ], 400);
        }

        // CRITICAL: Always read the initial total from the separate key and use it
        // This ensures we always return the correct total, even if the progress cache was updated incorrectly
        $initialTotalKey = "{$progressId}_initial_total";
        $initialTotal = Cache::get($initialTotalKey);

        // Use lock to ensure consistent read (prevents reading during write)
        $lock = Cache::lock("progress_read_{$progressId}", 5);

        try {
            if ($lock->get()) {
                $progress = Cache::get($progressId);
                $lock->release();
            } else {
                // If lock can't be acquired, try reading without lock (fallback)
                $progress = Cache::get($progressId);
            }
        } catch (\Throwable $lockError) {
            // Fallback: read without lock
            $progress = Cache::get($progressId);
        }

        if (!$progress) {
            return response()->json([
                'status' => 404,
                'message' => 'Progress not found',
                'data' => null,
            ], 404);
        }

        // Ensure progress has all required fields
        $progress = array_merge([
            'total' => 0,
            'processed' => 0,
            'errors' => 0,
            'status' => 'processing',
            'current_variant' => null,
        ], $progress);

        // CRITICAL: Override the total with the initial total if it exists
        // This ensures we always return the correct total, even if it was incorrectly updated
        if ($initialTotal !== null && $initialTotal > 0) {
            $progress['total'] = $initialTotal;
        }

        return response()->json([
            'status' => 200,
            'message' => 'Progress retrieved successfully',
            'data' => $progress,
        ], 200);
    }
}
