<?php

namespace Miladmodaresi\Taamito\Jobs;

use Miladmodaresi\Taamito\Base\BaseJob;
use Miladmodaresi\Taamito\Model\TaamSync;
use Miladmodaresi\Taamito\Services\ProductService;

class ProductJob implements BaseJob
{
    protected $products       = [];
    protected $categories       = [];
    protected $token            = '';
    protected $remoteProducts = [];
    protected $productService  = null;

    public function getLocalIds()
    {
        $syncData = new TaamSync();
        $data = $syncData->where('name', 'product')->where('status', 2)->get();
        $this->products = $data->pluck('remote_id', 'local_id');
        $user = taamitoApp()->getOption('user');

        $data = $syncData->where('name', 'category')->where('status', 2)->get();
        $this->categories = $data->pluck('remote_id', 'local_id');

        $this->token = $user['token'];
    }
    public function __construct($lastSyncModel)
    {
        $this->getLocalIds();
        $syncData = new TaamSync;
        $this->productService = new ProductService;
        $productModel = $syncData->where('name', 'products')->where('status', 2)->first();
        if (!$productModel->exists())
            $productModel = (new TaamSync(['name' => 'products', 'status' => 1]))->create();

        $this->process($productModel, 1, isset($lastSyncModel->data['last_sync_at']) ? $lastSyncModel->data['last_sync_at'] : null);
    }

    public function repair()
    {
        $syncData = new TaamSync();
        $data = $syncData->where('name', 'product')->where('status', 0)->get();
        foreach ($data as $item) {
            $entity = $item->data;
            $product = $entity['product'];
            switch ($entity['step']) {
                case 1:
                    $this->productService->find($item['local_id']);
                    if (count($product['prices']) > 1)
                        $this->productService->setAttributes($product);
                case 2:
                    $this->productService->find($item['local_id']);
                    if (count($product['tags']))
                        $this->productService->setTags($product['tags']);
                case 3:
                    $this->productService->find($item['local_id']);
                    $this->productService->setImagesRemote($product);
            }
        }
    }

    public function process($model, $page = 1, $lastSyncAt = null)
    {
        $queryParams = '';

        if ($lastSyncAt)
            $queryParams = 'updated_at=' . $lastSyncAt;

        if ($queryParams)
            $queryParams = $queryParams . '&page_size=20&page=' .  $page;
        else
            $queryParams = $queryParams . 'page_size=20&page=' . $page;

        $domain = taamitoApp()->getOption('domain');

        $response = taamitoApi()->setSubDomain($domain)->setAuth($this->token)
            ->get('wp/products?' . $queryParams);

        $this->remoteProducts = $response;
        foreach ($this->remoteProducts->entity->data as $product) {
            $convertToArray = json_decode(json_encode($product), true);
            
            $categories = [];

            foreach ($convertToArray['category_ids'] as $categoryId)
                $categories[] = $this->categories[$categoryId];

            $convertToArray['category_ids'] = $categories;
            if (!isset($this->products[$product->id]) && !$product->deleted_at) {
                $productModel = (new TaamSync(['name' => 'product', 'status' => 1, 'remote_id' => $product->id, 'data' => ['product' => $product]]))->create();
                try {
                    $product = $this->create($convertToArray, $productModel);
                    $productModel->update(['status' => 2]);
                } catch (\Throwable $th) {
                    \Sentry\captureMessage('error: ' . $th->getMessage());
                    $productModel->update(['status' => 0]);
                    //throw $th;
                }
            } else if (isset($this->products[$product->id]) && !$product->deleted_at) {
                $product = $this->update($this->products[$product->id], $convertToArray);
            } else if (isset($this->products[$product->id]) && $product->deleted_at) {
                $product = $this->delete($this->products[$product->id]);
            }
        }
        if ($this->remoteProducts->entity->last_page > $page)
            $this->process($model, ++$page, $lastSyncAt);
    }

    private function create($input, $model)
    {
        $this->productService->create($input, count($input['prices']) > 1);

        $data = $model->data;
        $data['step'] = 1;
        $model->update(['data' => $data, 'local_id' => $this->productService->get()['id']]);

        if (count($input['prices']) > 1)
            $this->productService->setAttributes($input);

        $data = $model->data;
        $data['step'] = 2;
        $model->update(['data' => $data]);

        if (count($input['tags']))
            $this->productService->setTags($input['tags']);

        $data = $model->data;
        $data['step'] = 3;
        $model->update(['data' => $data]);

        $this->productService->setImagesRemote($input);
        $data = $model->data;
        $data['step'] = 4;
        $model->update(['data' => $data]);

        $productData = $this->productService->get();
        $this->syncProductPriceMappings($productData['id'], $input['prices'] ?? [], $model->remote_id ?? null);

        return $productData;
    }
    private function update($id, $input)
    {
        $this->productService->update($id, $input, count($input['prices']) > 1);

        if (count($input['prices']) > 1)
            $this->productService->setAttributes($input);

        if (count($input['tags']))
            $this->productService->setTags($input['tags']);

        $this->productService->setImagesRemote($input);

        $this->syncProductPriceMappings($id, $input['prices'] ?? [], $this->getRemoteProductIdByLocalId($id));
    }
    private function delete($id)
    {
        $this->deleteProductPriceMappings($id);
        $this->productService->delete($id);
    }

    private function syncProductPriceMappings($productId, array $prices, $remoteProductId = null)
    {
        if (!$productId || empty($prices)) {
            return;
        }

        $priceMap = $this->productService->getPriceLocalMap();
        $product = wc_get_product($productId);

        if (!$product) {
            return;
        }

        foreach ($prices as $price) {
            $remotePriceId = $price['id'] ?? null;
            if (!$remotePriceId) {
                continue;
            }

            $localPriceId = $priceMap[$remotePriceId] ?? $this->resolveLocalPriceId($product, $price);

            if (!$localPriceId) {
                \Sentry\captureMessage("Taamito: missing local price mapping for product {$productId} and price {$remotePriceId}");
                continue;
            }

            $this->upsertProductPriceSync($localPriceId, $remotePriceId, $productId, $remoteProductId, $price);
        }
    }

    private function resolveLocalPriceId($product, array $price)
    {
        $priceCode = $price['code'] ?? null;

        if ($priceCode) {
            if ($product->is_type('variable')) {
                foreach ($product->get_children() as $childId) {
                    $variation = wc_get_product($childId);
                    if ($variation && $variation->get_sku() === $priceCode) {
                        return $childId;
                    }
                }
            }

            if ($product->get_sku() === $priceCode) {
                return $product->get_id();
            }
        }

        if (!$product->is_type('variable')) {
            return $product->get_id();
        }

        return null;
    }

    private function upsertProductPriceSync($localId, $remoteId, $productId, $remoteProductId, array $price)
    {
        $payload = [
            'name' => 'product_price',
            'local_id' => $localId,
            'remote_id' => $remoteId,
            'status' => 2,
            'data' => [
                'product_local_id' => $productId,
                'product_remote_id' => $remoteProductId,
                'price' => $price,
            ],
        ];

        $existing = (new TaamSync())->where('name', 'product_price')->where('local_id', $localId)->first();

        if ($existing && $existing->exists()) {
            $existing->update($payload);
            return;
        }

        (new TaamSync($payload))->create();
    }

    private function deleteProductPriceMappings($productId)
    {
        $localIds = [$productId];
        $product = wc_get_product($productId);

        if ($product && $product->is_type('variable')) {
            $localIds = array_merge($localIds, $product->get_children());
        }

        foreach (array_unique($localIds) as $localId) {
            (new TaamSync())->where('name', 'product_price')->where('local_id', $localId)->delete();
        }
    }

    private function getRemoteProductIdByLocalId($localId)
    {
        $remoteId = array_search($localId, $this->products, true);
        if ($remoteId === false) {
            return null;
        }

        return $remoteId;
    }
}
