<?php

namespace App\Jobs;

use App\Product;
use App\ProductDetail;
use App\ProductDetailOptionDetail;
use App\ProductOption;
use App\ProductOptionDetail;
use Illuminate\Bus\Queueable;
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessProductDetail implements ShouldQueue
{
    use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $product;

    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 3600;

    /**
     * Indicate if the job should be marked as failed on timeout.
     *
     * @var bool
     */
    public $failOnTimeout = false;

    /**
     * Create a new job instance.
     *
     * @param $product
     */
    public function __construct(Product $product)
    {
        $this->onQueue(config('queue.connections.redis.queue'));
        $this->product = $product->withoutRelations();
    }

    /**
     * @return bool
     */
    public function isFailOnTimeout(): bool
    {
        return $this->failOnTimeout;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        try {
            $listGroup = [];
            $options = ProductOption::select('id')->where('product_id', $this->product->id)->get();
            foreach ($options as $option) {
                $itemIds = ProductOptionDetail::select('id')->where('product_option_id', $option->id)->pluck('id')->toArray();
                if(count($itemIds) > 0) $listGroup[] = $itemIds;
            }

            $productDetails = [];
            $groupItems = $this->combinations($listGroup);
            foreach ($groupItems as $gKey => $gIt) {
                $productDetails[] = [
                    'sku'     => ($gKey + 1),
                    'code'    => implode("_", $gIt),
                    'options' => $gIt,
                ];
            }

            foreach ($productDetails as $item) {
                $productDetail = ProductDetail::create([
                    'product_id'   => $this->product->id,
                    'sku'          => $this->product->sku . '_' . $item['sku'],
                    'slug'         => $this->product->sku . '_' . $item['sku'],
                    'code'         => md5($this->product->sku . "_" . $item['code']),
                    'price'        => $this->product->default_price,
                    'position'     => 0,
                    'is_activated' => 1,
                    'created_at'   => date('Y-m-d H:i:s'),
                    'updated_at'   => date('Y-m-d H:i:s')
                ]);

                foreach ($item['options'] as $oItem) {
                    ProductDetailOptionDetail::create([
                        'product_detail_id'        => $productDetail->id,
                        'product_option_detail_id' => $oItem,
                        'created_at'               => date('Y-m-d H:i:s'),
                        'updated_at'               => date('Y-m-d H:i:s')
                    ]);
                }
            }
        } catch (\Exception $exception) {
            logger("Update product detail error: " . $exception->getMessage());
        }
    }

    private function combinations($arrays, $i = 0)
    {
        if (!isset($arrays[$i])) {
            return array();
        }

        if ($i == count($arrays) - 1) {
            return $arrays[$i];
        }

        $tmp = $this->combinations($arrays, $i + 1);
        $result = array();

        foreach ($arrays[$i] as $v) {
            foreach ($tmp as $t) {
                $result[] = is_array($t) ? array_merge(array($v), $t) : array($v, $t);
            }
        }

        return $result;
    }
}
