<?php

namespace App\Http\Controllers\Api\Desktop;

use App\Http\Controllers\Controller;
use App\Models\ShopProduct;
use App\Models\ShopProductPrice;
use App\Models\ShopProductStock;
use App\Models\Account;
use App\Models\ChartOfAccount;
use App\Models\ShopInvoice;
use App\Models\ShopInvoiceItem;
use App\Models\ShopInvoiceReturn;
use App\Models\ShopInvoiceReturnItem;
use App\Models\ShopGoodsReceipt;
use App\Models\ShopGoodsReceiptItem;
use App\Models\ShopContact;
use App\Models\ShopStock;
use App\Models\ShopContactAccountTransaction;
use App\Models\ShopExpenseCategory;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;

class PushController extends Controller
{
    /**
     * Step 1: Push Local User Password Changes
     * Sends user password changes made locally to the server
     */
    public function pushUserPasswordChanges(Request $request): JsonResponse
    {
        // TODO: Implementation will be added later
        return response()->json(['message' => 'Method not implemented yet']);
    }

    /**
     * Step 2: Push Local Product Updates (edits)
     * Sends product edits made locally to the server
     */
    public function pushProductUpdates(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => 'required|integer|exists:accounts,id',
                'updates' => 'nullable|array',
                'updates.*.sync_id' => 'required|integer',
                'updates.*.model_id' => 'required|string',
                'updates.*.data' => 'required|array',
                'updates.*.data.name' => 'required|string',
                'updates.*.data.sku' => 'required|string',
                'updates.*.data.price' => 'required|array',
                'updates.*.data.price.cost_price' => 'numeric',
                'updates.*.data.price.selling_price' => 'numeric',
                'updates.*.data.stock' => 'nullable|array',
                'updates.*.data.stock.*.quantity' => 'numeric',
                'updates.*.data.stock.*.base_to_unit' => 'nullable|numeric',
                'updates.*.data.stock.*.low_stock_threshold' => 'nullable|numeric',
                'updates.*.data.stock.*.stock_code' => 'nullable|string|max:50',
                'updates.*.data.is_active' => 'boolean',
            ]);

            $shopId = (string) $request->input('shop_id');
            $results = [
                'updates' => ['success' => [], 'failed' => []],
            ];

            if ($request->has('updates') && is_array($request->updates) && count($request->updates) > 0) {
                $result = $this->handleBulkUpdateShopProducts($shopId, $request->updates);
                $results['updates'] = $result;
            }

            return response()->json([
                'success' => true,
                'message' => 'Product updates synced successfully',
                'data' => $results,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Product updates sync failed', [
                'error' => $e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
                'error_details' => [
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'exception' => get_class($e),
                ],
                'trace' => config('app.debug') ? $e->getTraceAsString() : null,
            ], 500);
        }
    }

    /**
     * Step 3: Push Local New Products
     * Sends newly created products from local to the server
     */
    public function pushNewProducts(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => 'required|integer|exists:accounts,id',
                'creates' => 'nullable|array',
                'creates.*.sync_id' => 'required|integer',
                'creates.*.model_id' => 'required|string',
                'creates.*.data' => 'required|array',
                'creates.*.data.name' => 'required|string',
                'creates.*.data.sku' => 'required|string',
                'creates.*.data.price' => 'required|array',
                'creates.*.data.price.cost_price' => 'numeric',
                'creates.*.data.price.selling_price' => 'numeric',
                'creates.*.data.stock' => 'nullable|array',
                'creates.*.data.stock.*.quantity' => 'numeric',
                'creates.*.data.stock.*.base_to_unit' => 'nullable|numeric',
                'creates.*.data.stock.*.low_stock_threshold' => 'nullable|numeric',
                'creates.*.data.stock.*.stock_code' => 'nullable|string|max:50',
                'creates.*.data.is_active' => 'boolean',
            ]);

            $shopId = (string) $request->input('shop_id');
            $results = [
                'creates' => ['success' => [], 'failed' => []],
            ];

            if ($request->has('creates') && is_array($request->creates) && count($request->creates) > 0) {
                $result = $this->handleBulkCreateShopProducts($shopId, $request->creates);
                $results['creates'] = $result;
            }

            return response()->json([
                'success' => true,
                'message' => 'Products synced successfully',
                'data' => $results,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Product sync failed', [
                'error' => $e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
                'error_details' => [
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'exception' => get_class($e),
                ],
                'trace' => config('app.debug') ? $e->getTraceAsString() : null,
            ], 500);
        }
    }

    /**
     * Step 4: Push Local Customer Edits
     * Sends customer edits made locally to the server
     */
    public function pushCustomerEdits(Request $request): JsonResponse
    {
        // TODO: Implementation will be added later
        return response()->json(['message' => 'Method not implemented yet']);
    }

    /**
     * Step 5: Push Local New Customers
     * Sends newly created customers from local to the server
     */
    public function pushNewCustomers(Request $request): JsonResponse
    {
        // TODO: Implementation will be added later
        return response()->json(['message' => 'Method not implemented yet']);
    }

    /**
     * Step 6: Push Local Customer Account Updates
     * Sends customer account updates (credits, payments) from local to the server
     */
    public function pushCustomerAccountUpdates(Request $request): JsonResponse
    {
        // TODO: Implementation will be added later
        return response()->json(['message' => 'Method not implemented yet']);
    }

    /**
     * Step 7: Push Local Stock Entries
     * Sends stock entries made locally to the server
     */
    public function pushStockEntries(Request $request): JsonResponse
    {
        // TODO: Implementation will be added later
        return response()->json(['message' => 'Method not implemented yet']);
    }

    /**
     * Sync Shop Products (Creates, Updates, Deletes)
     * Handles bulk sync of shop products from desktop POS
     *
     * Features:
     * - Separate DB transactions for each operation type
     * - Idempotent: Safe to retry if internet connection is lost
     * - Handles items in multiple operations (create + update + delete)
     * - Resolves missing server_id by looking up existing records
     * - Returns shop_product IDs for newly created products
     */
    public function pushProducts(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => 'required|integer|exists:accounts,id',
                'creates' => 'nullable|array',
                'creates.*.sync_id' => 'required|integer',
                'creates.*.model_id' => 'required|integer',
                'creates.*.data' => 'required|array',
                'updates' => 'nullable|array',
                'updates.*.sync_id' => 'required|integer',
                'updates.*.model_id' => 'required|integer',
                'updates.*.server_id' => 'nullable|integer',
                'updates.*.data' => 'required|array',
                'deletes' => 'nullable|array',
                'deletes.*.sync_id' => 'required|integer',
                'deletes.*.model_id' => 'required|integer',
                'deletes.*.server_id' => 'nullable|integer',
            ]);

            $shopId = (string) $request->input('shop_id');
            $createdServerIds = [];
            $results = [
                'creates' => ['success' => [], 'failed' => []],
                'updates' => ['success' => [], 'failed' => []],
                'deletes' => ['success' => [], 'failed' => []],
            ];

            // ============================================
            // STEP 1: Handle Creates - BULK OPTIMIZED
            // ============================================
            if ($request->has('creates') && is_array($request->creates) && count($request->creates) > 0) {
                DB::beginTransaction();
                try {
                    $result = $this->handleBulkCreateShopProducts($shopId, $request->creates);
                    $results['creates'] = $result;
                    $createdServerIds = $result['server_id_map'] ?? [];
                    DB::commit();
                } catch (\Exception $e) {
                    DB::rollBack();
                    Log::error('Transaction failed for creates', [
                        'error' => $e->getMessage(),
                        'trace' => $e->getTraceAsString(),
                    ]);
                    throw $e;
                }
            }

            // ============================================
            // STEP 2: Handle Updates - BULK OPTIMIZED
            // ============================================
            if ($request->has('updates') && is_array($request->updates) && count($request->updates) > 0) {
                DB::beginTransaction();
                try {
                    $result = $this->handleBulkUpdateShopProducts($shopId, $request->updates, $createdServerIds);
                    $results['updates'] = $result;
                    DB::commit();
                } catch (\Exception $e) {
                    DB::rollBack();
                    Log::error('Transaction failed for updates', [
                        'error' => $e->getMessage(),
                        'trace' => $e->getTraceAsString(),
                    ]);
                    throw $e;
                }
            }

            // ============================================
            // STEP 3: Handle Deletes - BULK OPTIMIZED
            // ============================================
            if ($request->has('deletes') && is_array($request->deletes) && count($request->deletes) > 0) {
                DB::beginTransaction();
                try {
                    $result = $this->handleBulkDeleteShopProducts($shopId, $request->deletes, $createdServerIds);
                    $results['deletes'] = $result;
                    DB::commit();
                } catch (\Exception $e) {
                    DB::rollBack();
                    Log::error('Transaction failed for deletes', [
                        'error' => $e->getMessage(),
                        'trace' => $e->getTraceAsString(),
                    ]);
                    throw $e;
                }
            }

            // Remove internal tracking from response
            unset($results['creates']['server_id_map']);

            return response()->json([
                'success' => true,
                'message' => 'Shop products synced successfully',
                'data' => $results,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Shop product sync failed', [
                'error' => $e->getMessage() . ' - ' . $e->getFile() . ' - ' . $e->getLine(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(), // Direct error message for desktop app
                'error' => $e->getMessage(),
                'error_details' => [
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'exception' => get_class($e),
                ],
                'trace' => config('app.debug') ? $e->getTraceAsString() : null,
            ], 500);
        }
    }

    /**
     * Find shop_product ID by model_id and shop_id
     * Used when server_id is missing in update/delete operations
     * Tries multiple lookup methods in order of reliability
     */
    private function findShopProductIdByModelId(int $shopId, ?int $modelId, array $data = []): ?int
    {
        if (!$modelId) {
            return null;
        }

        // Method 1: Find by account_id (model_id) + shop_id (most reliable)
        $shopProduct = ShopProduct::where('account_id', $modelId)
            ->where('shop_id', $shopId)
            ->first();

        if ($shopProduct) {
            return $shopProduct->id;
        }

        // Method 2: Find by local_id if provided in data
        if (isset($data['id'])) {
            $shopProduct = ShopProduct::where('local_id', $data['id'])
                ->where('shop_id', $shopId)
                ->first();

            if ($shopProduct) {
                return $shopProduct->id;
            }
        }

        // Method 3: Find by SKU if provided
        if (isset($data['sku'])) {
            $shopProduct = ShopProduct::where('shop_product_sku', $data['sku'])
                ->where('shop_id', $shopId)
                ->first();

            if ($shopProduct) {
                return $shopProduct->id;
            }
        }

        // Method 4: Find by barcode if provided
        if (isset($data['barcode'])) {
            $shopProduct = ShopProduct::where('shop_product_barcode', $data['barcode'])
                ->where('shop_id', $shopId)
                ->first();

            if ($shopProduct) {
                return $shopProduct->id;
            }
        }

        return null;
    }

    /**
     * Bulk create shop products - OPTIMIZED
     */
    private function handleBulkCreateShopProducts(int $shopId, array $creates): array
    {
        $success = [];
        $failed = [];
        $serverIdMap = [];

        // Step 1: Validate all accounts exist in bulk
        $modelIds = collect($creates)->pluck('model_id')->unique()->toArray();
        $accounts = Account::whereIn('id', $modelIds)
            ->where('model_type', 'Item')
            ->get()
            ->keyBy('id');

        // Step 1.5: Create missing Account (Item) records
        $missingModelIds = [];
        foreach ($creates as $create) {
            $modelId = $create['model_id'];
            if (!isset($accounts[$modelId])) {
                $missingModelIds[] = $modelId;
            }
        }

        if (!empty($missingModelIds)) {
            // Find default Finished Goods category
            $inventoryAccount = ChartOfAccount::where('name', 'Inventory')->first();
            $finishedGoodsCategory = null;

            if ($inventoryAccount) {
                $finishedGoodsCategory = ChartOfAccount::where('parent_id', $inventoryAccount->id)
                    ->where('name', 'Finished Goods')
                    ->where('is_active', true)
                    ->first();
            }

            // If no Finished Goods category, try to find any active category under Inventory
            if (!$finishedGoodsCategory && $inventoryAccount) {
                $finishedGoodsCategory = ChartOfAccount::where('parent_id', $inventoryAccount->id)
                    ->where('is_active', true)
                    ->first();
            }

            // Default to chart_of_account_id = 53 if still not found (based on code patterns)
            $defaultChartOfAccountId = $finishedGoodsCategory ? $finishedGoodsCategory->id : 53;

            // Validate that the chart_of_account_id exists
            if ($defaultChartOfAccountId && !ChartOfAccount::find($defaultChartOfAccountId)) {
                // If default ID doesn't exist, try to find any active chart of account
                $anyChartOfAccount = ChartOfAccount::where('is_active', true)->first();
                if ($anyChartOfAccount) {
                    $defaultChartOfAccountId = $anyChartOfAccount->id;
                } else {
                    Log::error('No valid chart_of_account_id found for creating Account (Item)', [
                        'inventory_account' => $inventoryAccount ? $inventoryAccount->id : null,
                        'finished_goods_category' => $finishedGoodsCategory ? $finishedGoodsCategory->id : null,
                    ]);
                    // If still no valid ID, we'll let it fail with a clear error message
                }
            }

            // Create missing accounts
            foreach ($creates as $create) {
                $modelId = $create['model_id'];
                if (!isset($accounts[$modelId]) && in_array($modelId, $missingModelIds)) {
                    $data = $create['data'];

                    try {
                        // Check if Account with this SKU already exists
                        $existingAccount = null;
                        if (!empty($data['sku'])) {
                            $existingAccount = Account::where('sku', $data['sku'])
                                ->where('model_type', 'Item')
                                ->first();
                        }

                        if ($existingAccount) {
                            // Use existing account instead of creating new one
                            $accounts[$modelId] = $existingAccount;
                            unset($missingModelIds[array_search($modelId, $missingModelIds)]);

                            Log::info('Using existing Account (Item) for model_id: ' . $modelId, [
                                'model_id' => $modelId,
                                'account_id' => $existingAccount->id,
                                'sku' => $data['sku'],
                            ]);
                            continue; // Skip creation
                        }

                        // Create Account (Item) only if it doesn't exist
                        $accountData = [
                            'name' => $data['name'] ?? 'Unnamed Product',
                            'sku' => $data['sku'] ?? 'SKU-' . $modelId,
                            'barcode' => $data['barcode'] ?? null,
                            'chart_of_account_id' => $defaultChartOfAccountId,
                            'model_type' => 'Item',
                            'is_shop_item' => 1, // Mark as shop item
                            'model_id' => 0, // Temporary, will update after creation
                            'code' => 'INV-' . ($data['sku'] ?? $modelId),
                            'description' => 'Auto-created from desktop POS sync',
                            'is_active' => $data['is_active'] ?? true,
                            'status' => ($data['is_active'] ?? true) ? 'active' : 'inactive',
                            'balance' => 0.00,
                        ];

                        $account = Account::create($accountData);
                        $account->model_id = $account->id; // Self-reference
                        $account->save();

                        $accounts[$modelId] = $account;
                        unset($missingModelIds[array_search($modelId, $missingModelIds)]);

                        Log::info('Auto-created Account (Item) for model_id: ' . $modelId, [
                            'model_id' => $modelId,
                            'account_id' => $account->id,
                            'name' => $account->name,
                        ]);
                    } catch (\Exception $e) {
                        Log::error('Failed to create Account (Item) for model_id: ' . $modelId, [
                            'model_id' => $modelId,
                            'data' => $data,
                            'error' => $e->getMessage(),
                            'trace' => $e->getTraceAsString(),
                        ]);
                        // Continue - will be handled in failed array below
                    }
                }
            }
        }

        // Step 2: Check existing shop products in bulk
        $existingProducts = ShopProduct::where('shop_id', $shopId)
            ->whereIn('account_id', $modelIds)
            ->get()
            ->keyBy('account_id');

        // Also check by local_id if provided
        $localIds = collect($creates)->pluck('data.id')->filter()->toArray();
        $existingByLocalId = collect();
        if (!empty($localIds)) {
            $existingByLocalId = ShopProduct::where('shop_id', $shopId)
                ->whereIn('local_id', $localIds)
                ->get()
                ->keyBy('local_id');
        }

        // Step 3: Prepare bulk insert data
        $toInsert = [];
        $toUpdatePrice = [];
        $toUpdateStock = [];

        foreach ($creates as $create) {
            try {
                $modelId = $create['model_id'];
                $data = $create['data'];
                $syncId = $create['sync_id'];

                // Validate account exists
                if (!isset($accounts[$modelId])) {
                    $failed[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'error' => "Account (Item) with ID {$modelId} not found",
                    ];
                    continue;
                }

                $account = $accounts[$modelId];

                // Check if already exists
                if (isset($existingProducts[$modelId])) {
                    $existing = $existingProducts[$modelId];
                    $success[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'server_id' => $existing->id,
                        'shop_product_id' => $existing->id,
                        'already_exists' => true,
                    ];
                    $serverIdMap[$modelId] = $existing->id;
                    continue;
                }

                // Check by local_id
                if (isset($data['id']) && $existingByLocalId->has($data['id'])) {
                    $existing = $existingByLocalId[$data['id']];
                    $success[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'server_id' => $existing->id,
                        'shop_product_id' => $existing->id,
                        'already_exists' => true,
                    ];
                    $serverIdMap[$modelId] = $existing->id;
                    continue;
                }

                // Prepare for bulk insert
                $toInsert[] = [
                    'account_id' => $account->id,
                    'shop_id' => $shopId,
                    'local_id' => $data['id'] ?? null,
                    'name' => $data['name'] ?? $account->name,
                    'shop_product_sku' => $data['sku'] ?? $account->sku,
                    'shop_product_barcode' => $data['barcode'] ?? $account->barcode,
                    'is_active' => $data['is_active'] ?? true,
                    'created_at' => now(),
                    'updated_at' => now(),
                    '_sync_id' => $syncId, // Temporary field for mapping
                    '_model_id' => $modelId, // Temporary field for mapping
                ];

                // Track for price/stock updates
                $toUpdatePrice[$syncId] = [
                    'sync_id' => $syncId,
                    'model_id' => $modelId,
                    'local_id' => $data['id'] ?? null,
                    'account_id' => $account->id,
                    // 'cost_price' => $data['cost_price'] ?? 0,
                    'selling_price' => $data['price'] ?? 0,
                ];

                $toUpdateStock[$syncId] = [
                    'sync_id' => $syncId,
                    'model_id' => $modelId,
                    'local_id' => $data['id'] ?? null,
                    'account_id' => $account->id,
                    'stock_data' => $data['stock'] ?? [],
                ];

            } catch (\Exception $e) {
                $failed[] = [
                    'sync_id' => $create['sync_id'] ?? null,
                    'model_id' => $create['model_id'] ?? null,
                    'error' => $e->getMessage(),
                ];
                Log::error('Failed to prepare create shop product', [
                    'create' => $create,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        // Step 4: Bulk insert shop products
        if (!empty($toInsert)) {
            // Remove temporary fields before insert
            $insertData = array_map(function($item) {
                unset($item['_sync_id'], $item['_model_id']);
                return $item;
            }, $toInsert);

            DB::table('shop_products')->insert($insertData);

            // Get inserted IDs using account_id + shop_id mapping
            $insertedAccountIds = collect($toInsert)->pluck('account_id')->toArray();
            $insertedLocalIds = collect($toInsert)->pluck('local_id')->filter()->toArray();

            $insertedProducts = ShopProduct::where('shop_id', $shopId)
                ->where(function($query) use ($insertedAccountIds, $insertedLocalIds) {
                    $query->whereIn('account_id', $insertedAccountIds)
                        ->orWhereIn('local_id', $insertedLocalIds);
                })
                ->whereNull('deleted_at')
                ->orderBy('id', 'desc')
                ->limit(count($toInsert))
                ->get(['id', 'account_id', 'local_id']);

            // Create mapping for inserted products
            $productMap = [];
            foreach ($insertedProducts as $product) {
                $productMap["account_{$product->account_id}"] = $product;
                if ($product->local_id) {
                    $productMap["local_{$product->local_id}"] = $product;
                }
            }

            // Step 5: Create success responses and prepare price/stock data
            $priceData = [];
            $stockData = [];

            foreach ($toInsert as $insert) {
                $syncId = $insert['_sync_id'] ?? null;
                $modelId = $insert['_model_id'] ?? null;
                $priceInfo = $toUpdatePrice[$syncId] ?? null;
                $stockInfo = $toUpdateStock[$syncId] ?? null;

                if (!$syncId || !$modelId) {
                    continue;
                }

                // Find inserted product
                $key = $insert['local_id'] ? "local_{$insert['local_id']}" : "account_{$insert['account_id']}";
                $insertedProduct = $productMap[$key] ?? null;

                if ($insertedProduct) {
                    $success[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'server_id' => $insertedProduct->id,
                        'shop_product_id' => $insertedProduct->id,
                        'already_exists' => false,
                    ];
                    $serverIdMap[$modelId] = $insertedProduct->id;

                    // Prepare price/stock bulk inserts
                    if ($priceInfo) {
                        $priceData[] = [
                            'shop_product_id' => $insertedProduct->id,
                            'shop_id' => $shopId,
                            // 'cost_price' => $priceInfo['cost_price'] ?? 0,
                            'selling_price' => $priceInfo['selling_price'] ?? 0,
                            'is_synced' => 1, // New prices start as unsynced
                            'created_at' => now(),
                            'updated_at' => now(),
                        ];
                    }

                    if ($stockInfo && !empty($stockInfo['stock_data'])) {
                        // Handle stock as array of objects
                        $stockArray = is_array($stockInfo['stock_data']) ? $stockInfo['stock_data'] : [$stockInfo['stock_data']];

                        foreach ($stockArray as $stockItem) {
                            if (is_array($stockItem)) {
                                $stockData[] = [
                                    'shop_product_id' => $insertedProduct->id,
                                    'shop_id' => $shopId,
                                    'quantity' => $stockItem['quantity'] ?? 0,
                                    'low_stock_threshold' => $stockItem['low_stock_threshold'] ?? 0,
                                    'base_to_unit' => $stockItem['base_to_unit'] ?? null,
                                    'length' => $stockItem['length'] ?? null,
                                    'stock_code' => $stockItem['stock_code'] ?? null,
                                    'created_at' => now(),
                                    'updated_at' => now(),
                                ];
                            }
                        }
                    }
                }
            }

            // Step 6: Bulk insert prices and stocks
            if (!empty($priceData)) {
                DB::table('shop_product_prices')->insert($priceData);
            }

            if (!empty($stockData)) {
                DB::table('shop_product_stocks')->insert($stockData);
            }
        }

        return [
            'success' => $success,
            'failed' => $failed,
            'server_id_map' => $serverIdMap,
        ];
    }

    /**
     * Bulk update shop products - OPTIMIZED
     */
    private function handleBulkUpdateShopProducts(int $shopId, array $updates, array $createdServerIds): array
    {
        $success = [];
        $failed = [];

        // Step 1: Resolve all server_ids
        $resolvedUpdates = [];
        $modelIdsToResolve = [];

        foreach ($updates as $update) {
            if (empty($update['server_id'])) {
                $modelId = $update['model_id'] ?? null;
                if ($modelId && isset($createdServerIds[$modelId])) {
                    $update['server_id'] = $createdServerIds[$modelId];
                } else {
                    $modelIdsToResolve[] = $modelId;
                }
            }
            $resolvedUpdates[] = $update;
        }

        // Step 2: Bulk lookup missing server_ids
        if (!empty($modelIdsToResolve)) {
            $foundProducts = ShopProduct::where('shop_id', $shopId)
                ->whereIn('account_id', array_unique($modelIdsToResolve))
                ->get(['id', 'account_id'])
                ->keyBy('account_id');

            foreach ($resolvedUpdates as &$update) {
                if (empty($update['server_id'])) {
                    $modelId = $update['model_id'] ?? null;
                    if ($modelId && isset($foundProducts[$modelId])) {
                        $update['server_id'] = $foundProducts[$modelId]->id;
                    }
                }
            }
        }

        // Step 3: Separate updates with and without server_id
        $updatesWithServerId = [];
        $updatesWithoutServerId = [];

        foreach ($resolvedUpdates as $update) {
            if (!empty($update['server_id'])) {
                $updatesWithServerId[] = $update;
            } else {
                $updatesWithoutServerId[] = $update;
            }
        }

        // Step 4: Bulk update products with server_id
        if (!empty($updatesWithServerId)) {
            $serverIds = collect($updatesWithServerId)->pluck('server_id')->toArray();
            $existingProducts = ShopProduct::withTrashed()
                ->where('shop_id', $shopId)
                ->whereIn('id', $serverIds)
                ->get()
                ->keyBy('id');

            // Group updates by field
            $nameUpdates = [];
            $skuUpdates = [];
            $barcodeUpdates = [];
            $activeUpdates = [];
            $restoreIds = [];

            foreach ($updatesWithServerId as $update) {
                $serverId = $update['server_id'];
                $data = $update['data'];

                if (!isset($existingProducts[$serverId])) {
                    $failed[] = [
                        'sync_id' => $update['sync_id'] ?? null,
                        'server_id' => $serverId,
                        'model_id' => $update['model_id'] ?? null,
                        'error' => "ShopProduct with ID {$serverId} not found",
                    ];
                    continue;
                }

                $product = $existingProducts[$serverId];

                // Restore if deleted
                if ($product->trashed()) {
                    $restoreIds[] = $serverId;
                }

                // Collect field updates
                if (isset($data['name'])) {
                    $nameUpdates[$serverId] = $data['name'];
                }
                if (isset($data['sku'])) {
                    $skuUpdates[$serverId] = $data['sku'];
                }
                if (isset($data['barcode'])) {
                    $barcodeUpdates[$serverId] = $data['barcode'];
                }
                if (isset($data['is_active'])) {
                    $activeUpdates[$serverId] = $data['is_active'];
                }
            }

            // Bulk restore
            if (!empty($restoreIds)) {
                ShopProduct::withTrashed()
                    ->whereIn('id', $restoreIds)
                    ->restore();
            }

            // Bulk update fields
            $updatedProductIds = [];
            foreach ($nameUpdates as $id => $value) {
                DB::table('shop_products')->where('id', $id)->update(['name' => $value]);
                $updatedProductIds[] = $id;
            }
            foreach ($skuUpdates as $id => $value) {
                DB::table('shop_products')->where('id', $id)->update(['shop_product_sku' => $value]);
                $updatedProductIds[] = $id;
            }
            foreach ($barcodeUpdates as $id => $value) {
                DB::table('shop_products')->where('id', $id)->update(['shop_product_barcode' => $value]);
                $updatedProductIds[] = $id;
            }
            foreach ($activeUpdates as $id => $value) {
                DB::table('shop_products')->where('id', $id)->update(['is_active' => $value]);
                $updatedProductIds[] = $id;
            }

            // Mark all prices as unsynced for updated shop products
            if (!empty($updatedProductIds)) {
                DB::table('shop_product_prices')
                    ->whereIn('shop_product_id', array_unique($updatedProductIds))
                    ->where('shop_id', $shopId)
                    ->update(['is_synced' => 1]);
            }

            // Bulk update prices
            $priceUpdates = [];
            foreach ($updatesWithServerId as $update) {
                if (isset($update['data']['price'])
                    // || isset($update['data']['cost_price'])
                ) {
                    $priceUpdates[] = [
                        'shop_product_id' => $update['server_id'],
                        'shop_id' => $shopId,
                        // 'cost_price' => $update['data']['cost_price'] ?? 0,
                        'selling_price' => $update['data']['price'] ?? 0,
                    ];
                }
            }

            if (!empty($priceUpdates)) {
                foreach ($priceUpdates as $priceUpdate) {
                    DB::table('shop_product_prices')->updateOrInsert(
                        [
                            'shop_product_id' => $priceUpdate['shop_product_id'],
                            'shop_id' => $shopId,
                        ],
                        [
                            // 'cost_price' => $priceUpdate['cost_price'],
                            'selling_price' => $priceUpdate['selling_price'],
                            // 'is_synced' => 0, // Mark as unsynced when price is updated
                            'updated_at' => now(),
                        ]
                    );
                }
            }

            // Bulk update stocks
            $stockUpdates = [];
            foreach ($updatesWithServerId as $update) {
                if (isset($update['data']['stock'])) {
                    $stockArray = is_array($update['data']['stock']) ? $update['data']['stock'] : [$update['data']['stock']];

                    foreach ($stockArray as $stockItem) {
                        if (is_array($stockItem)) {
                            $stockUpdates[] = [
                                'shop_product_id' => $update['server_id'],
                                'shop_id' => $shopId,
                                'quantity' => $stockItem['quantity'] ?? 0,
                                'low_stock_threshold' => $stockItem['low_stock_threshold'] ?? 0,
                                'base_to_unit' => $stockItem['base_to_unit'] ?? null,
                                'length' => $stockItem['length'] ?? null,
                                'stock_code' => $stockItem['stock_code'] ?? null,
                            ];
                        }
                    }
                }
            }

            if (!empty($stockUpdates)) {
                foreach ($stockUpdates as $stockUpdate) {
                    DB::table('shop_product_stocks')->updateOrInsert(
                        [
                            'shop_product_id' => $stockUpdate['shop_product_id'],
                            'shop_id' => $shopId,
                        ],
                        [
                            'quantity' => $stockUpdate['quantity'],
                            'low_stock_threshold' => $stockUpdate['low_stock_threshold'] ?? 0,
                            'base_to_unit' => $stockUpdate['base_to_unit'],
                            'length' => $stockUpdate['length'],
                            'stock_code' => $stockUpdate['stock_code'],
                            'updated_at' => now(),
                        ]
                    );
                }
            }

            // Build success responses
            foreach ($updatesWithServerId as $update) {
                $product = $existingProducts[$update['server_id']] ?? null;
                if ($product) {
                    $success[] = [
                        'sync_id' => $update['sync_id'] ?? null,
                        'server_id' => $update['server_id'],
                        'model_id' => $product->account_id,
                    ];
                }
            }
        }

        // Step 5: Handle updates without server_id (create them)
        if (!empty($updatesWithoutServerId)) {
            $createResult = $this->handleBulkCreateShopProducts($shopId, array_map(function($update) {
                return [
                    'sync_id' => $update['sync_id'],
                    'model_id' => $update['model_id'],
                    'data' => $update['data'],
                ];
            }, $updatesWithoutServerId));

            $success = array_merge($success, $createResult['success']);
            $failed = array_merge($failed, $createResult['failed']);
        }

        return [
            'success' => $success,
            'failed' => $failed,
        ];
    }

    /**
     * Bulk delete shop products - OPTIMIZED
     */
    private function handleBulkDeleteShopProducts(int $shopId, array $deletes, array $createdServerIds): array
    {
        $success = [];
        $failed = [];

        // Step 1: Resolve all server_ids
        $resolvedDeletes = [];
        $modelIdsToResolve = [];

        foreach ($deletes as $delete) {
            if (empty($delete['server_id'])) {
                $modelId = $delete['model_id'] ?? null;
                if ($modelId && isset($createdServerIds[$modelId])) {
                    $delete['server_id'] = $createdServerIds[$modelId];
                } else {
                    $modelIdsToResolve[] = $modelId;
                }
            }
            $resolvedDeletes[] = $delete;
        }

        // Step 2: Bulk lookup missing server_ids
        if (!empty($modelIdsToResolve)) {
            $foundProducts = ShopProduct::where('shop_id', $shopId)
                ->whereIn('account_id', array_unique($modelIdsToResolve))
                ->get(['id', 'account_id'])
                ->keyBy('account_id');

            foreach ($resolvedDeletes as &$delete) {
                if (empty($delete['server_id'])) {
                    $modelId = $delete['model_id'] ?? null;
                    if ($modelId && isset($foundProducts[$modelId])) {
                        $delete['server_id'] = $foundProducts[$modelId]->id;
                    }
                }
            }
        }

        // Step 3: Separate deletes with and without server_id
        $deletesWithServerId = collect($resolvedDeletes)->filter(fn($d) => !empty($d['server_id']))->toArray();
        $deletesWithoutServerId = collect($resolvedDeletes)->filter(fn($d) => empty($d['server_id']))->toArray();

        // Step 4: Handle deletes without server_id (idempotent success)
        foreach ($deletesWithoutServerId as $delete) {
            $success[] = [
                'sync_id' => $delete['sync_id'] ?? null,
                'server_id' => null,
                'model_id' => $delete['model_id'] ?? null,
                'message' => 'ShopProduct not found (may already be deleted or never existed)',
                'already_deleted' => true,
            ];
        }

        // Step 5: Bulk soft delete
        if (!empty($deletesWithServerId)) {
            $serverIds = collect($deletesWithServerId)->pluck('server_id')->toArray();

            // Get products to check if already deleted
            $products = ShopProduct::withTrashed()
                ->where('shop_id', $shopId)
                ->whereIn('id', $serverIds)
                ->get()
                ->keyBy('id');

            // Separate already deleted and to delete
            $alreadyDeleted = [];
            $toDelete = [];

            foreach ($deletesWithServerId as $delete) {
                $serverId = $delete['server_id'];
                if (!isset($products[$serverId])) {
                    $success[] = [
                        'sync_id' => $delete['sync_id'] ?? null,
                        'server_id' => $serverId,
                        'message' => 'ShopProduct not found (may already be deleted)',
                        'already_deleted' => true,
                    ];
                } elseif ($products[$serverId]->trashed()) {
                    $alreadyDeleted[] = $delete;
                } else {
                    $toDelete[] = $serverId;
                }
            }

            // Bulk soft delete
            if (!empty($toDelete)) {
                ShopProduct::whereIn('id', $toDelete)->delete();

                // Bulk delete related prices and stocks
                ShopProductPrice::whereIn('shop_product_id', $toDelete)
                    ->where('shop_id', $shopId)
                    ->delete();

                ShopProductStock::whereIn('shop_product_id', $toDelete)
                    ->where('shop_id', $shopId)
                    ->delete();
            }

            // Build success responses
            foreach ($deletesWithServerId as $delete) {
                $serverId = $delete['server_id'];
                $product = $products[$serverId] ?? null;

                if (!$product) {
                    continue; // Already handled above
                }

                $success[] = [
                    'sync_id' => $delete['sync_id'] ?? null,
                    'server_id' => $serverId,
                    'model_id' => $product->account_id,
                    'already_deleted' => $product->trashed(),
                    'message' => $product->trashed() ? 'ShopProduct already deleted' : null,
                ];
            }
        }

        return [
            'success' => $success,
            'failed' => $failed,
        ];
    }

    /**
     * Push Invoices
     * Handles bulk sync of invoices from desktop POS
     */
    public function pushInvoices(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
                'updated_status_records' => 'nullable|array',
                'updated_status_records.*.invoice_code' => 'required|string',
                'updated_status_records.*.status' => 'nullable|string',
                'updated_status_records.*.paid_amount' => 'nullable|numeric',
                'updated_status_records.*.discount' => 'nullable|numeric',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopInvoice::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'shop_invoice_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $invoice = ShopInvoice::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'contact_code' => $record['contact_code'] ?? '',
                                'branch_code' => $data['branch_code'] ?? '',
                                'total_amount' => $data['total_amount'] ?? 0,
                                'discount_amount' => $data['discount_amount'] ?? 0,
                                'paid_amount' => $data['paid_amount'] ?? 0,
                                'status' => $data['status'] ?? 'unpaid',
                                'is_tax_inclusive' => $data['is_tax_inclusive'] ?? false,
                                'tax_rate' => $data['tax_rate'] ?? 0,
                                'tax_amount' => $data['tax_amount'] ?? 0,

                                'invoice_date' => $data['invoice_date'] ?? now()->toDateString(),
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoice->id,
                                'code' => $code,
                                'server_id' => $invoice->id,
                                'shop_invoice_id' => $invoice->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $invoice = $existingItem ? ShopInvoice::find($existingItem->id) : null;

                            if (!$invoice) {
                                $invoice = ShopInvoice::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'contact_code' => $record['contact_code'] ?? '',
                                        'branch_code' => $data['branch_code'] ?? '',
                                        'total_amount' => $data['total_amount'] ?? 0,
                                        'discount_amount' => $data['discount_amount'] ?? 0,
                                        'paid_amount' => $data['paid_amount'] ?? 0,
                                        'status' => $data['status'] ?? 'unpaid',
                                        'is_tax_inclusive' => $data['is_tax_inclusive'] ?? false,
                                        'tax_rate' => $data['tax_rate'] ?? 0,
                                        'tax_amount' => $data['tax_amount'] ?? 0,

                                        'invoice_date' => $data['invoice_date'] ?? now()->toDateString(),
                                    ]
                                );

                                $existingRecords->put($lookupKey, $invoice);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $invoice->id,
                                    'code' => $code,
                                    'server_id' => $invoice->id,
                                    'shop_invoice_id' => $invoice->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $invoice->update([
                                'contact_code' => $record['contact_code'] ?? $invoice->contact_code,
                                'branch_code' => $data['branch_code'] ?? $invoice->branch_code,
                                'total_amount' => $data['total_amount'] ?? $invoice->total_amount,
                                'discount_amount' => $data['discount_amount'] ?? $invoice->discount_amount,
                                'paid_amount' => $data['paid_amount'] ?? $invoice->paid_amount,
                                'status' => $data['status'] ?? $invoice->status,
                                'invoice_date' => $data['invoice_date'] ?? $invoice->invoice_date,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoice->id,
                                'code' => $code,
                                'server_id' => $invoice->id,
                                'shop_invoice_id' => $invoice->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $invoice = $existingItem ? ShopInvoice::find($existingItem->id) : null;

                            if (!$invoice) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Invoice not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $invoiceId = $invoice->id;
                            $invoice->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoiceId,
                                'code' => $code,
                                'server_id' => $invoiceId,
                                'shop_invoice_id' => $invoiceId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process invoice record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                // Process updated_status_records
                $updatedStatusRecords = $request->input('updated_status_records', []);
                if (!empty($updatedStatusRecords)) {
                    foreach ($updatedStatusRecords as $statusRecord) {
                        try {
                            $invoice = ShopInvoice::where('code', $statusRecord['invoice_code'])
                                ->where('shop_id', $shopId)
                                ->first();

                            if ($invoice) {
                                $updateData = [];

                                if (isset($statusRecord['status'])) {
                                    $updateData['status'] = $statusRecord['status'];
                                }

                                if (isset($statusRecord['paid_amount'])) {
                                    $updateData['paid_amount'] = $statusRecord['paid_amount'];
                                }

                                if (isset($statusRecord['discount'])) {
                                    $updateData['discount_amount'] = $statusRecord['discount'];
                                }

                                if (!empty($updateData)) {
                                    $invoice->update($updateData);
                                    $success[] = [
                                        'sync_id' => 'status_update_' . $statusRecord['invoice_code'],
                                        'type' => 'status_update',
                                        'code' => $statusRecord['invoice_code'],
                                        'message' => 'Status updated successfully'
                                    ];
                                }
                            } else {
                                $failed[] = [
                                    'sync_id' => 'status_update_' . $statusRecord['invoice_code'],
                                    'type' => 'status_update',
                                    'code' => $statusRecord['invoice_code'],
                                    'error' => 'Invoice not found'
                                ];
                            }
                        } catch (\Exception $e) {
                            $failed[] = [
                                'sync_id' => 'status_update_' . ($statusRecord['invoice_code'] ?? 'unknown'),
                                'type' => 'status_update',
                                'code' => $statusRecord['invoice_code'] ?? 'unknown',
                                'error' => $e->getMessage()
                            ];
                        }
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Invoices synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Invoice sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Invoice Items
     * Handles bulk sync of invoice items from desktop POS
     */
    public function pushInvoiceItems(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.invoice_code' => 'nullable|string',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopInvoiceItem::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $invoiceCode = $record['invoice_code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $item = ShopInvoiceItem::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'invoice_code' => $invoiceCode,
                                'stock_code' => $record['stock_code'] ?? '',
                                'local_product_code' => $record['local_product_code'] ?? '',
                                'server_product_code' => $record['server_product_code'] ?? '',
                                'quantity' => $data['quantity'] ?? 0,
                                'length' => $data['length'] ?? null,
                                'unit_price' => $data['unit_price'] ?? 0,
                                'discount_per_unit' => $data['discount_per_unit'] ?? 0,
                                'total_price' => $data['total_price'] ?? 0,
                                'sold_length' => $data['sold_length'] ?? 0,
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopInvoiceItem::find($existingItem->id) : null;

                            if (!$item) {
                                $item = ShopInvoiceItem::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'invoice_code' => $invoiceCode,
                                        'stock_code' => $record['stock_code'] ?? '',
                                        'local_product_code' => $record['local_product_code'] ?? '',
                                        'server_product_code' => $record['server_product_code'] ?? '',
                                        'quantity' => $data['quantity'] ?? 0,
                                        'length' => $data['length'] ?? null,
                                        'unit_price' => $data['unit_price'] ?? 0,
                                        'discount_per_unit' => $data['discount_per_unit'] ?? 0,
                                        'total_price' => $data['total_price'] ?? 0,
                                        'sold_length' => $data['sold_length'] ?? 0,
                                    ]
                                );

                                $existingRecords->put($lookupKey, $item);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $item->id,
                                    'code' => $code,
                                    'server_id' => $item->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $item->update([
                                'invoice_code' => $invoiceCode,
                                'stock_code' => $record['stock_code'] ?? $item->stock_code,
                                'local_product_code' => $record['local_product_code'] ?? $item->local_product_code,
                                'server_product_code' => $record['server_product_code'] ?? $item->server_product_code,
                                'quantity' => $data['quantity'] ?? $item->quantity,
                                'length' => $data['length'] ?? $item->length,
                                'unit_price' => $data['unit_price'] ?? $item->unit_price,
                                'discount_per_unit' => $data['discount_per_unit'] ?? $item->discount_per_unit,
                                'total_price' => $data['total_price'] ?? $item->total_price,
                                'sold_length' => $data['sold_length'] ?? $item->sold_length,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopInvoiceItem::find($existingItem->id) : null;

                            if (!$item) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Invoice item not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $itemId = $item->id;
                            $item->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $itemId,
                                'code' => $code,
                                'server_id' => $itemId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process invoice item record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Invoice items synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Invoice items sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Invoice Returns
     */
    public function pushInvoiceReturns(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.contact_code' => 'required|string',
                'records.*.invoice_code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
                'updated_status_records' => 'nullable|array',
                'updated_status_records.*.invoice_return_code' => 'required|string',
                'updated_status_records.*.status' => 'nullable|string',
                'updated_status_records.*.paid_amount' => 'nullable|numeric',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopInvoiceReturn::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {

                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }
                            // dd($record);
                            $invoiceReturn = ShopInvoiceReturn::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'contact_code' => $record['contact_code'] ?? '',
                                'invoice_code' => $record['invoice_code'] ?? '',
                                'branch_code' => $data['branch_code'] ?? '',
                                'total_amount' => $data['total_amount'] ?? 0,
                                'status' => $data['status'] ?? 'pending',
                                'is_tax_inclusive' => $data['is_tax_inclusive'] ?? false,
                                'tax_rate' => $data['tax_rate'] ?? 0,
                                'tax_amount' => $data['tax_amount'] ?? 0,
                                'return_date' => $data['return_date'] ?? now()->toDateString(),
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoiceReturn->id,
                                'code' => $code,
                                'server_id' => $invoiceReturn->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $invoiceReturn = $existingItem ? ShopInvoiceReturn::find($existingItem->id) : null;

                            if (!$invoiceReturn) {
                                $invoiceReturn = ShopInvoiceReturn::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'contact_code' => $record['contact_code'] ?? '',
                                        'invoice_code' => $data['invoice_code'] ?? '',
                                        'branch_code' => $data['branch_code'] ?? '',
                                        'total_amount' => $data['total_amount'] ?? 0,
                                        'status' => $data['status'] ?? 'pending',
                                        'is_tax_inclusive' => $data['is_tax_inclusive'] ?? false,
                                        'tax_rate' => $data['tax_rate'] ?? 0,
                                        'tax_amount' => $data['tax_amount'] ?? 0,

                                        'return_date' => $data['return_date'] ?? now()->toDateString(),
                                    ]
                                );

                                $existingRecords->put($lookupKey, $invoiceReturn);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $invoiceReturn->id,
                                    'code' => $code,
                                    'server_id' => $invoiceReturn->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $invoiceReturn->update([
                                'contact_code' => $record['contact_code'] ?? $invoiceReturn->contact_code,
                                'invoice_code' => $data['invoice_code'] ?? $invoiceReturn->invoice_code,
                                'branch_code' => $data['branch_code'] ?? $invoiceReturn->branch_code,
                                'total_amount' => $data['total_amount'] ?? $invoiceReturn->total_amount,
                                'status' => $data['status'] ?? $invoiceReturn->status,
                                'return_date' => $data['return_date'] ?? $invoiceReturn->return_date,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoiceReturn->id,
                                'code' => $code,
                                'server_id' => $invoiceReturn->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $invoiceReturn = $existingItem ? ShopInvoiceReturn::find($existingItem->id) : null;

                            if (!$invoiceReturn) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Invoice return not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $invoiceReturnId = $invoiceReturn->id;
                            $invoiceReturn->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $invoiceReturnId,
                                'code' => $code,
                                'server_id' => $invoiceReturnId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process invoice return record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                // Process updated_status_records
                $updatedStatusRecords = $request->input('updated_status_records', []);
                if (!empty($updatedStatusRecords)) {
                    foreach ($updatedStatusRecords as $statusRecord) {
                        try {
                            $invoiceReturn = ShopInvoiceReturn::where('code', $statusRecord['invoice_return_code'])
                                ->where('shop_id', $shopId)
                                ->first();

                            if ($invoiceReturn) {
                                $updateData = [];

                                if (isset($statusRecord['status'])) {
                                    $updateData['status'] = $statusRecord['status'];
                                }

                                if (isset($statusRecord['paid_amount'])) {
                                    $updateData['paid_amount'] = $statusRecord['paid_amount'];
                                }

                                if (!empty($updateData)) {
                                    $invoiceReturn->update($updateData);
                                    $success[] = [
                                        'sync_id' => 'status_update_' . $statusRecord['invoice_return_code'],
                                        'type' => 'status_update',
                                        'code' => $statusRecord['invoice_return_code'],
                                        'message' => 'Status updated successfully'
                                    ];
                                }
                            } else {
                                $failed[] = [
                                    'sync_id' => 'status_update_' . $statusRecord['invoice_return_code'],
                                    'type' => 'status_update',
                                    'code' => $statusRecord['invoice_return_code'],
                                    'error' => 'Invoice return not found'
                                ];
                            }
                        } catch (\Exception $e) {
                            $failed[] = [
                                'sync_id' => 'status_update_' . ($statusRecord['invoice_return_code'] ?? 'unknown'),
                                'type' => 'status_update',
                                'code' => $statusRecord['invoice_return_code'] ?? 'unknown',
                                'error' => $e->getMessage()
                            ];
                        }
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Invoice returns synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Invoice returns sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Invoice Return Items
     */
    public function pushInvoiceReturnItems(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.invoice_return_code' => 'nullable|string',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopInvoiceReturnItem::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['data']['invoice_item_id'];
                        $invoiceReturnCode = $record['invoice_return_code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $item = ShopInvoiceReturnItem::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'invoice_return_code' => $invoiceReturnCode,
                                'stock_code' => $record['stock_code'] ?? '',
                                'local_product_code' => $record['local_product_code'] ?? '',
                                'server_product_code' => $record['server_product_code'] ?? '',
                                'quantity' => $data['quantity'] ?? 0,
                                'length' => $data['length'] ?? null,
                                'unit_price' => $data['unit_price'] ?? 0,
                                'total_price' => $data['total_price'] ?? 0,
                                'returned_length' => $data['returned_length'] ?? 0,
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopInvoiceReturnItem::find($existingItem->id) : null;

                            if (!$item) {
                                $item = ShopInvoiceReturnItem::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'invoice_return_code' => $invoiceReturnCode,
                                        'stock_code' => $record['stock_code'] ?? '',
                                        'local_product_code' => $record['local_product_code'] ?? '',
                                        'server_product_code' => $record['server_product_code'] ?? '',
                                        'quantity' => $data['quantity'] ?? 0,
                                        'length' => $data['length'] ?? null,
                                        'unit_price' => $data['unit_price'] ?? 0,
                                        'total_price' => $data['total_price'] ?? 0,
                                        'returned_length' => $data['returned_length'] ?? 0,
                                    ]
                                );

                                $existingRecords->put($lookupKey, $item);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $item->id,
                                    'code' => $code,
                                    'server_id' => $item->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $item->update([
                                'invoice_return_code' => $invoiceReturnCode,
                                'stock_code' => $record['stock_code'] ?? $item->stock_code,
                                'local_product_code' => $record['local_product_code'] ?? $item->local_product_code,
                                'server_product_code' => $record['server_product_code'] ?? $item->server_product_code,
                                'quantity' => $data['quantity'] ?? $item->quantity,
                                'length' => $data['length'] ?? $item->length,
                                'unit_price' => $data['unit_price'] ?? $item->unit_price,
                                'total_price' => $data['total_price'] ?? $item->total_price,
                                'returned_length' => $data['returned_length'] ?? $item->returned_length,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopInvoiceReturnItem::find($existingItem->id) : null;

                            if (!$item) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Invoice return item not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $itemId = $item->id;
                            $item->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $itemId,
                                'code' => $code,
                                'server_id' => $itemId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process invoice return item record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Invoice return items synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Invoice return items sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Goods Receipts
     */
    public function pushGoodsReceipts(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopGoodsReceipt::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $receipt = ShopGoodsReceipt::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'delivery_note_code' => $data['delivery_note_code'] ?? null,
                                'contact_code' => $record['contact_code'] ?? '',
                                'branch_code' => $data['branch_code'] ?? '',
                                'total_amount' => $data['total_amount'] ?? 0,
                                'paid_amount' => $data['paid_amount'] ?? 0,
                                'status' => $data['status'] ?? 'unpaid',
                                'receipt_date' => $data['receipt_date'] ?? now()->toDateString(),
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $receipt->id,
                                'code' => $code,
                                'server_id' => $receipt->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $receipt = $existingItem ? ShopGoodsReceipt::find($existingItem->id) : null;

                            if (!$receipt) {
                                $receipt = ShopGoodsReceipt::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'delivery_note_code' => $data['delivery_note_code'] ?? null,
                                        'contact_code' => $record['contact_code'] ?? '',
                                        'branch_code' => $data['branch_code'] ?? '',
                                        'total_amount' => $data['total_amount'] ?? 0,
                                        'paid_amount' => $data['paid_amount'] ?? 0,
                                        'status' => $data['status'] ?? 'unpaid',
                                        'receipt_date' => $data['receipt_date'] ?? now()->toDateString(),
                                    ]
                                );

                                $existingRecords->put($lookupKey, $receipt);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $receipt->id,
                                    'code' => $code,
                                    'server_id' => $receipt->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $receipt->update([
                                'delivery_note_code' => $data['delivery_note_code'] ?? $receipt->delivery_note_code,
                                'contact_code' => $record['contact_code'] ?? $receipt->contact_code,
                                'branch_code' => $data['branch_code'] ?? $receipt->branch_code,
                                'total_amount' => $data['total_amount'] ?? $receipt->total_amount,
                                'paid_amount' => $data['paid_amount'] ?? $receipt->paid_amount,
                                'status' => $data['status'] ?? $receipt->status,
                                'receipt_date' => $data['receipt_date'] ?? $receipt->receipt_date,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $receipt->id,
                                'code' => $code,
                                'server_id' => $receipt->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $receipt = $existingItem ? ShopGoodsReceipt::find($existingItem->id) : null;

                            if (!$receipt) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Goods receipt not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $receiptId = $receipt->id;
                            $receipt->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $receiptId,
                                'code' => $code,
                                'server_id' => $receiptId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process goods receipt record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Goods receipts synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Goods receipts sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Goods Receipt Items
     */
    public function pushGoodsReceiptItems(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.goods_receipt_code' => 'nullable|string',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopGoodsReceiptItem::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $goodsReceiptCode = $record['goods_receipt_code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $item = ShopGoodsReceiptItem::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'goods_receipt_code' => $goodsReceiptCode,
                                'stock_code' => $data['stock_code'] ?? '',
                                'local_product_code' => $record['local_product_code'] ?? '',
                                'server_product_code' => $record['server_product_code'] ?? '',
                                'quantity' => $data['quantity'] ?? 0,
                                'length' => $data['length'] ?? null,
                                'unit_price' => $data['unit_price'] ?? 0,
                                'total_price' => $data['total_price'] ?? 0,
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopGoodsReceiptItem::find($existingItem->id) : null;

                            if (!$item) {
                                $item = ShopGoodsReceiptItem::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'goods_receipt_code' => $goodsReceiptCode,
                                        'stock_code' => $data['stock_code'] ?? '',
                                        'local_product_code' => $record['local_product_code'] ?? '',
                                        'server_product_code' => $record['server_product_code'] ?? '',
                                        'quantity' => $data['quantity'] ?? 0,
                                        'length' => $data['length'] ?? null,
                                        'unit_price' => $data['unit_price'] ?? 0,
                                        'total_price' => $data['total_price'] ?? 0,
                                    ]
                                );

                                $existingRecords->put($lookupKey, $item);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $item->id,
                                    'code' => $code,
                                    'server_id' => $item->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $item->update([
                                'goods_receipt_code' => $goodsReceiptCode,
                                'stock_code' => $data['stock_code'] ?? $item->stock_code,
                                'local_product_code' => $record['local_product_code'] ?? $item->local_product_code,
                                'server_product_code' => $record['server_product_code'] ?? $item->server_product_code,
                                'quantity' => $data['quantity'] ?? $item->quantity,
                                'length' => $data['length'] ?? $item->length,
                                'unit_price' => $data['unit_price'] ?? $item->unit_price,
                                'total_price' => $data['total_price'] ?? $item->total_price,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $item->id,
                                'code' => $code,
                                'server_id' => $item->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $item = $existingItem ? ShopGoodsReceiptItem::find($existingItem->id) : null;

                            if (!$item) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Goods receipt item not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $itemId = $item->id;
                            $item->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $itemId,
                                'code' => $code,
                                'server_id' => $itemId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process goods receipt item record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Goods receipt items synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Goods receipt items sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Contacts
     */
    public function pushContacts(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopContact::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'shop_contact_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $contact = ShopContact::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'contact_type' => $data['contact_type'] ?? 'customer',
                                'name' => $data['name'] ?? '',
                                'phone' => $data['phone'] ?? null,
                                'address' => $data['address'] ?? null,
                                'credit_limit' => $data['credit_limit'] ?? 0,
                                'branch_code' => $data['branch_code'] ?? '',
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $contact->id,
                                'code' => $code,
                                'server_id' => $contact->id,
                                'shop_contact_id' => $contact->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $contact = $existingItem ? ShopContact::find($existingItem->id) : null;

                            if (!$contact) {
                                $contact = ShopContact::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'contact_type' => $data['contact_type'] ?? 'customer',
                                        'name' => $data['name'] ?? '',
                                        'phone' => $data['phone'] ?? null,
                                        'address' => $data['address'] ?? null,
                                        'credit_limit' => $data['credit_limit'] ?? 0,
                                        'branch_code' => $data['branch_code'] ?? '',
                                    ]
                                );

                                $existingRecords->put($lookupKey, $contact);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $contact->id,
                                    'code' => $code,
                                    'server_id' => $contact->id,
                                    'shop_contact_id' => $contact->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $contact->update([
                                'contact_type' => $data['contact_type'] ?? $contact->contact_type,
                                'name' => $data['name'] ?? $contact->name,
                                'phone' => $data['phone'] ?? $contact->phone,
                                'address' => $data['address'] ?? $contact->address,
                                'credit_limit' => $data['credit_limit'] ?? $contact->credit_limit,
                                'branch_code' => $data['branch_code'] ?? $contact->branch_code,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $contact->id,
                                'code' => $code,
                                'server_id' => $contact->id,
                                'shop_contact_id' => $contact->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $contact = $existingItem ? ShopContact::find($existingItem->id) : null;

                            if (!$contact) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Contact not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $contactId = $contact->id;
                            $contact->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $contactId,
                                'code' => $code,
                                'server_id' => $contactId,
                                'shop_contact_id' => $contactId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process contact record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Contacts synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Contacts sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Stocks
     */
    public function pushStocks(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.local_product_code' => 'required',
                'records.*.server_product_code' => 'required',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopStock::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'shop_stock_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $stock = ShopStock::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'local_product_code' => $record['local_product_code'] ?? null,
                                'server_product_code' => $record['server_product_code'] ?? null,
                                'branch_code' => $data['branch_code'] ?? '',
                                'length' => $data['length'] ?? null,
                                'quantity' => $data['quantity'] ?? 0,
                                'cost_price' => $data['cost_price'] ?? 0,
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $stock->id,
                                'code' => $code,
                                'server_id' => $stock->id,
                                'shop_stock_id' => $stock->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $stock = $existingItem ? ShopStock::find($existingItem->id) : null;

                            if (!$stock) {
                                $stock = ShopStock::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'local_product_code' => $record['local_product_code'] ?? null,
                                        'server_product_code' => $record['server_product_code'] ?? null,
                                        'branch_code' => $data['branch_code'] ?? '',
                                        'length' => $data['length'] ?? null,
                                        'quantity' => $data['quantity'] ?? 0,
                                        'cost_price' => $data['cost_price'] ?? 0,
                                    ]
                                );

                                $existingRecords->put($lookupKey, $stock);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $stock->id,
                                    'code' => $code,
                                    'server_id' => $stock->id,
                                    'shop_stock_id' => $stock->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $stock->update([
                                'local_product_code' => $record['local_product_code'] ?? $stock->local_product_code,
                                'server_product_code' => $record['server_product_code'] ?? $stock->server_product_code,
                                'branch_code' => $data['branch_code'] ?? $stock->branch_code,
                                'length' => $data['length'] ?? $stock->length,
                                'quantity' => $data['quantity'] ?? $stock->quantity,
                                'cost_price' => $data['cost_price'] ?? $stock->cost_price,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $stock->id,
                                'code' => $code,
                                'server_id' => $stock->id,
                                'shop_stock_id' => $stock->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $stock = $existingItem ? ShopStock::find($existingItem->id) : null;

                            if (!$stock) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Stock not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $stockId = $stock->id;
                            $stock->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $stockId,
                                'code' => $code,
                                'server_id' => $stockId,
                                'shop_stock_id' => $stockId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process stock record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Stocks synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Stocks sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Push Contact Account Transactions
     */
    public function pushContactAccountTransactions(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'last_sync_time' => 'nullable|date',
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.shop_id' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.contact_code' => 'nullable|string',
                'records.*.reference_code' => 'nullable|string',
                'records.*.transaction_code' => 'nullable|string',
                'records.*.employee_user_id' => 'nullable|integer',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
                'records.*.data.reference_type' => 'nullable|string',
                'records.*.data.transaction_type' => 'nullable|string',
                'records.*.data.account_code' => 'nullable|string',
                'records.*.data.expense_category_code' => 'nullable',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $success = [];
            $failed = [];

            DB::beginTransaction();
            try {
                // Bulk optimization: Pre-fetch all existing records in one query
                $allCodes = array_unique(array_column($records, 'code'));
                $existingRecords = ShopContactAccountTransaction::where('shop_id', $shopId)
                    ->whereIn('code', $allCodes)
                    ->get(['id', 'code', 'local_db_created_at'])
                    ->keyBy(function($item) {
                        return $item->code . '|' . $item->local_db_created_at->format('Y-m-d H:i:s');
                    });

                // Resolve each pushed `employee_user_id` (a users.id on this server) to the
                // employee's Account record (model_type='employee'), the same way
                // LicenseAPIController/SyncAPIController link a login-capable user to their
                // employee profile: by matching `username`. Resolved once per batch.
                $employeeUserIds = array_values(array_unique(array_filter(
                    array_column($records, 'employee_user_id')
                )));
                $employeeAccountIdByUserId = [];
                if (!empty($employeeUserIds)) {
                    $usernamesByUserId = User::whereIn('id', $employeeUserIds)->pluck('username', 'id');
                    $accountIdsByUsername = Account::where('model_type', 'employee')
                        ->whereIn('username', $usernamesByUserId->filter()->values())
                        ->pluck('id', 'username');

                    foreach ($usernamesByUserId as $userId => $username) {
                        if ($username && $accountIdsByUsername->has($username)) {
                            $employeeAccountIdByUserId[$userId] = $accountIdsByUsername[$username];
                        }
                    }
                }

                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $contactCode = $record['contact_code'] ?? '';
                        $referenceCode = $record['reference_code'] ?? '';
                        $data = $record['data'] ?? [];
                        $transactionCode = $record['transaction_code'] ?? ($data['code'] ?? null);
                        $localDbCreatedAt = Carbon::parse($record['created_at']);
                        $lookupKey = $code . '|' . $localDbCreatedAt->format('Y-m-d H:i:s');
                        $employeeAccountId = $employeeAccountIdByUserId[$record['employee_user_id'] ?? null] ?? null;

                        $referenceType = $data['reference_type'] ?? 'invoice';

                        // The desktop sends the expense category under `expense_category_id`
                        // (its value is the category code, e.g. "EC-53-00001"). Accept the
                        // legacy `expense_category_code` key too, for safety.
                        $expenseCategoryCode = $data['expense_category_id']
                            ?? $data['expense_category_code']
                            ?? null;

                        if ($action === 'create') {
                            $existing = $existingRecords[$lookupKey] ?? null;

                            if ($existing) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $existing->id,
                                    'code' => $code,
                                    'server_id' => $existing->id,
                                    'already_exists' => true,
                                ];
                                continue;
                            }

                            $transaction = ShopContactAccountTransaction::create([
                                'shop_id' => $shopId,
                                'code' => $code,
                                'contact_code' => $contactCode,
                                'account_code' => $data['account_code'] ?? null,
                                'employee_account_id' => $employeeAccountId,
                                'expense_category_code' => $expenseCategoryCode,
                                'transaction_code' => $transactionCode,
                                'reference_type' => $referenceType,
                                'reference_code' => $referenceCode,
                                'amount' => $data['amount'] ?? 0,
                                'transaction_type' => $data['transaction_type'] ?? 'debit',
                                'description' => $data['description'] ?? null,
                                'local_db_created_at' => $localDbCreatedAt,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $transaction->id,
                                'code' => $code,
                                'server_id' => $transaction->id,
                            ];
                        } elseif ($action === 'update') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $transaction = $existingItem ? ShopContactAccountTransaction::find($existingItem->id) : null;

                            if (!$transaction) {
                                $transaction = ShopContactAccountTransaction::updateOrCreate(
                                    [
                                        'shop_id' => $shopId,
                                        'code' => $code,
                                        'local_db_created_at' => $localDbCreatedAt,
                                    ],
                                    [
                                        'contact_code' => $contactCode,
                                        'account_code' => $data['account_code'] ?? null,
                                        'employee_account_id' => $employeeAccountId,
                                        'expense_category_code' => $expenseCategoryCode,
                                        'transaction_code' => $transactionCode,
                                        'reference_type' => $referenceType,
                                        'reference_code' => $referenceCode,
                                        'amount' => $data['amount'] ?? 0,
                                        'transaction_type' => $data['transaction_type'] ?? 'debit',
                                        'description' => $data['description'] ?? null,
                                    ]
                                );

                                $existingRecords->put($lookupKey, $transaction);

                                $success[] = [
                                    'sync_id' => $syncId,
                                    'id' => $transaction->id,
                                    'code' => $code,
                                    'server_id' => $transaction->id,
                                    'created_from_update' => true,
                                ];
                                continue;
                            }

                            $transaction->update([
                                'contact_code' => $contactCode,
                                'account_code' => $data['account_code'] ?? $transaction->account_code,
                                'employee_account_id' => $employeeAccountId ?? $transaction->employee_account_id,
                                'expense_category_code' => $expenseCategoryCode ?? $transaction->expense_category_code,
                                'transaction_code' => $transactionCode ?? $transaction->transaction_code,
                                'reference_type' => $referenceType,
                                'reference_code' => $referenceCode,
                                'amount' => $data['amount'] ?? $transaction->amount,
                                'transaction_type' => $data['transaction_type'] ?? $transaction->transaction_type,
                                'description' => $data['description'] ?? $transaction->description,
                            ]);

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $transaction->id,
                                'code' => $code,
                                'server_id' => $transaction->id,
                            ];
                        } elseif ($action === 'delete') {
                            $existingItem = $existingRecords[$lookupKey] ?? null;
                            $transaction = $existingItem ? ShopContactAccountTransaction::find($existingItem->id) : null;

                            if (!$transaction) {
                                $success[] = [
                                    'sync_id' => $syncId,
                                    'code' => $code,
                                    'message' => 'Transaction not found (may already be deleted)',
                                    'already_deleted' => true,
                                ];
                                continue;
                            }

                            $transactionId = $transaction->id;
                            $transaction->delete();

                            $success[] = [
                                'sync_id' => $syncId,
                                'id' => $transactionId,
                                'code' => $code,
                                'server_id' => $transactionId,
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'error' => $e->getMessage(),
                            'code' => $record['code'] ?? null,
                        ];
                        Log::error('Failed to process contact account transaction record', [
                            'record' => $record,
                            'error' => $e->getMessage(),
                        ]);
                    }
                }

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'message' => 'Contact account transactions synced successfully',
                'sync_time' => now()->toIso8601String(),
                'success' => $success,
                'failed' => $failed,
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Contact account transactions sync failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request' => $request->all(),
            ]);

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Handle bulk creation of shop products with stock data
     */
    private function handleBulkCreateProducts(string $shopId, array $creates): array
    {
        $success = [];
        $failed = [];

        DB::beginTransaction();
        try {
            // Step 1: Validate all accounts exist in bulk
            $modelIds = collect($creates)->pluck('model_id')->unique()->toArray();
            $accounts = Account::whereIn('id', $modelIds)
                ->where('model_type', 'Item')
                ->get()
                ->keyBy('id');

            // Step 1.5: Create missing Account (Item) records
            $missingModelIds = [];
            foreach ($creates as $create) {
                $modelId = $create['model_id'];
                if (!isset($accounts[$modelId])) {
                    $missingModelIds[] = $modelId;
                }
            }

            if (!empty($missingModelIds)) {
                // Create missing accounts
                foreach ($creates as $create) {
                    $modelId = $create['model_id'];
                    if (!isset($accounts[$modelId]) && in_array($modelId, $missingModelIds)) {
                        $data = $create['data'];

                        try {
                            // Create Account (Item)
                            $accountData = [
                                'name' => $data['name'] ?? 'Unnamed Product',
                                'sku' => $data['sku'] ?? 'SKU-' . $modelId,
                                'barcode' => $data['barcode'] ?? null,
                                'chart_of_account_id' => 53, // Default
                                'model_type' => 'Item',
                                'is_shop_item' => 1,
                                'model_id' => 0,
                                'code' => 'INV-' . ($data['sku'] ?? $modelId),
                                'description' => 'Created from desktop POS sync',
                                'is_active' => $data['is_active'] ?? true,
                                'status' => ($data['is_active'] ?? true) ? 'active' : 'inactive',
                                'balance' => 0.00,
                            ];

                            $account = Account::create($accountData);
                            $account->model_id = $account->id;
                            $account->save();

                            $accounts[$modelId] = $account;
                            unset($missingModelIds[array_search($modelId, $missingModelIds)]);
                        } catch (\Exception $e) {
                            Log::error('Failed to create Account (Item)', [
                                'model_id' => $modelId,
                                'error' => $e->getMessage(),
                            ]);
                        }
                    }
                }
            }

            // Step 2: Check existing shop products
            $existingProducts = ShopProduct::where('shop_id', $shopId)
                ->whereIn('account_id', $modelIds)
                ->get()
                ->keyBy('account_id');

            // Step 3: Process each create
            foreach ($creates as $create) {
                try {
                    $syncId = $create['sync_id'];
                    $modelId = $create['model_id'];
                    $data = $create['data'];

                    $account = $accounts[$modelId] ?? null;
                    if (!$account) {
                        $failed[] = [
                            'sync_id' => $syncId,
                            'model_id' => $modelId,
                            'error' => 'Account not found',
                        ];
                        continue;
                    }

                    // Create shop product if it doesn't exist
                    $shopProduct = $existingProducts[$modelId] ?? null;
                    if (!$shopProduct) {
                        $shopProduct = ShopProduct::create([
                            'account_id' => $account->id,
                            'shop_id' => $shopId,
                            'local_id' => null,
                            'name' => $data['name'] ?? $account->name,
                            'shop_product_sku' => $data['sku'] ?? $account->sku,
                            'shop_product_barcode' => $data['barcode'] ?? $account->barcode,
                            'is_active' => $data['is_active'] ?? true,
                        ]);
                    }

                    // Process stock data - REPLACE existing stock
                    if (isset($data['stock']) && is_array($data['stock'])) {
                        $this->processShopProductStock($shopProduct->id, $shopId, $data['stock']);
                    }

                    $success[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'server_id' => $shopProduct->id,
                    ];

                } catch (\Exception $e) {
                    $failed[] = [
                        'sync_id' => $create['sync_id'] ?? null,
                        'model_id' => $create['model_id'] ?? null,
                        'error' => $e->getMessage(),
                    ];
                    Log::error('Failed to create shop product', [
                        'create' => $create,
                        'error' => $e->getMessage(),
                    ]);
                }
            }

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }

        return ['success' => $success, 'failed' => $failed];
    }

    /**
     * Handle bulk updates of shop products with stock data
     */
    private function handleBulkUpdateProducts(string $shopId, array $updates): array
    {
        $success = [];
        $failed = [];

        DB::beginTransaction();
        try {
            // Step 1: Resolve all server_ids
            $resolvedUpdates = [];
            $modelIdsToResolve = [];

            foreach ($updates as $update) {
                if (empty($update['server_id'])) {
                    $modelId = $update['model_id'] ?? null;
                    if ($modelId) {
                        $modelIdsToResolve[] = $modelId;
                    }
                }
                $resolvedUpdates[] = $update;
            }

            // Step 2: Bulk lookup missing server_ids
            if (!empty($modelIdsToResolve)) {
                $foundProducts = ShopProduct::where('shop_id', $shopId)
                    ->whereIn('account_id', array_unique($modelIdsToResolve))
                    ->get(['id', 'account_id'])
                    ->keyBy('account_id');

                foreach ($resolvedUpdates as &$update) {
                    if (empty($update['server_id'])) {
                        $modelId = $update['model_id'] ?? null;
                        if ($modelId && isset($foundProducts[$modelId])) {
                            $update['server_id'] = $foundProducts[$modelId]->id;
                        }
                    }
                }
            }

            // Step 3: Process updates
            foreach ($resolvedUpdates as $update) {
                try {
                    $syncId = $update['sync_id'];
                    $modelId = $update['model_id'];
                    $serverId = $update['server_id'] ?? null;
                    $data = $update['data'];

                    // Find existing shop product
                    $shopProduct = null;
                    if ($serverId) {
                        $shopProduct = ShopProduct::withTrashed()->find($serverId);
                    } else {
                        // Try to find by SKU
                        $shopProduct = ShopProduct::where('shop_id', $shopId)
                            ->where('shop_product_sku', $data['sku'])
                            ->first();
                    }

                    if (!$shopProduct) {
                        $failed[] = [
                            'sync_id' => $syncId,
                            'model_id' => $modelId,
                            'error' => 'Shop product not found',
                        ];
                        continue;
                    }

                    // Restore if deleted
                    if ($shopProduct->trashed()) {
                        $shopProduct->restore();
                    }

                    // Update shop product
                    $shopProduct->update([
                        'name' => $data['name'] ?? $shopProduct->name,
                        'shop_product_sku' => $data['sku'] ?? $shopProduct->shop_product_sku,
                        'shop_product_barcode' => $data['barcode'] ?? $shopProduct->shop_product_barcode,
                        'is_active' => $data['is_active'] ?? $shopProduct->is_active,
                    ]);

                    // Process stock data - REPLACE existing stock
                    if (isset($data['stock']) && is_array($data['stock'])) {
                        $this->processShopProductStock($shopProduct->id, $shopId, $data['stock']);
                    }

                    $success[] = [
                        'sync_id' => $syncId,
                        'model_id' => $modelId,
                        'server_id' => $shopProduct->id,
                    ];

                } catch (\Exception $e) {
                    $failed[] = [
                        'sync_id' => $update['sync_id'] ?? null,
                        'model_id' => $update['model_id'] ?? null,
                        'error' => $e->getMessage(),
                    ];
                    Log::error('Failed to update shop product', [
                        'update' => $update,
                        'error' => $e->getMessage(),
                    ]);
                }
            }

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }

        return ['success' => $success, 'failed' => $failed];
    }


    /**
     * Process stock data for a shop product - REPLACE existing stock entries
     */
    private function processShopProductStock(int $shopProductId, string $shopId, array $stockRecords): void
    {
        // Delete existing stock entries for this shop product (REPLACE logic)
        ShopProductStock::where('shop_product_id', $shopProductId)->delete();

        foreach ($stockRecords as $stockRecord) {
            try {
                $quantity = $stockRecord['quantity'] ?? 0;
                $length = $stockRecord['base_to_unit'] ?? null;
                $lowStockThreshold = $stockRecord['low_stock_threshold'] ?? null;

                // Create stock entry for this shop product
                ShopProductStock::create([
                    'shop_product_id' => $shopProductId,
                    'shop_id' => $shopId,
                    'quantity' => $quantity,
                    'length' => $length,
                    'low_stock_threshold' => $lowStockThreshold,
                ]);

                Log::info('Stock created for shop product sync', [
                    'shop_product_id' => $shopProductId,
                    'shop_id' => $shopId,
                    'quantity' => $quantity,
                    'length' => $length,
                    'low_stock_threshold' => $lowStockThreshold,
                ]);

            } catch (\Exception $e) {
                Log::error('Failed to process stock record for shop product', [
                    'shop_product_id' => $shopProductId,
                    'stock_record' => $stockRecord,
                    'error' => $e->getMessage(),
                ]);
                // Continue processing other stock records
            }
        }
    }

    /**
     * Push Expense Categories
     * Handles sync of expense categories from desktop POS
     */
    public function pushExpenseCategories(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'shop_id' => ['required', function ($attribute, $value, $fail) {
                    if (!is_string($value) && !is_numeric($value)) {
                        $fail('The shop id must be a string or number.');
                    }
                }],
                'records' => 'required|array',
                'records.*.sync_id' => 'required|integer',
                'records.*.code' => 'required|string',
                'records.*.created_at' => 'required|date',
                'records.*.action' => 'required|in:create,update,delete',
                'records.*.data' => 'required_if:records.*.action,create,update|array',
            ]);

            $shopId = (string) $request->input('shop_id');
            $records = $request->input('records', []);

            $successful = [];
            $failed = [];

            DB::beginTransaction();
            try {
                foreach ($records as $record) {
                    try {
                        $action = $record['action'];
                        $syncId = $record['sync_id'];
                        $code = $record['code'];
                        $data = $record['data'] ?? [];
                        $localCreatedAt = Carbon::parse($record['created_at']);

                        if ($action === 'delete') {
                            $category = ShopExpenseCategory::where('shop_id', $shopId)
                                ->where('code', $code)
                                ->first();
                            
                            if ($category) {
                                $category->delete();
                            }

                            $successful[] = [
                                'sync_id' => $syncId,
                                'code' => $code,
                                'id' => $category ? $category->id : null
                            ];
                        } else {
                            // create or update
                            $category = ShopExpenseCategory::updateOrCreate(
                                [
                                    'shop_id' => $shopId,
                                    'code' => $code,
                                ],
                                [
                                    'name' => $data['name'] ?? '',
                                    'description' => $data['description'] ?? '',
                                    'local_db_created_at' => $localCreatedAt,
                                ]
                            );

                            $successful[] = [
                                'sync_id' => $syncId,
                                'code' => $code,
                                'id' => $category->id
                            ];
                        }
                    } catch (\Exception $e) {
                        $failed[] = [
                            'sync_id' => $record['sync_id'] ?? null,
                            'code' => $record['code'] ?? null,
                            'error' => $e->getMessage()
                        ];
                    }
                }
                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

            return response()->json([
                'success' => true,
                'successful' => $successful,
                'failed' => $failed
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 422);
        } catch (\Exception $e) {
            Log::error('Expense Category push failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ], 500);
        }
    }

}
