<?php

namespace Modules\Product\Services;

use Modules\Product\Enums\ProductStockStatusEnum;
use Modules\Product\Enums\ReportEnum;
use Modules\Product\Exports\ReportSalesExport;
use Modules\Product\Exports\StocklBalanceExport;
use Modules\Product\Exports\StockLedgerExport;
use Modules\Product\Interfaces\ProductRepositoryInterface;
use Modules\Product\Models\Product;
use Modules\Product\Models\ProductStock;

class ProductService
{
    private ProductRepositoryInterface $productRepository;

    public function __construct(ProductRepositoryInterface $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    public function get(array $request)
    {
        $builder = $this->productRepository->get($request);

        if (isset($request['valid']))
        {
            $builder->where('products.status', $request['valid']);
        }
        if (@$request['code']) {
            $builder->where('products.code', $request['code']);
        }
        if (@$request['title']) {
            $builder->where('sd.title', 'LIKE', '%' . $request['title'] . '%');
        }
        if (@$request['canteen_id']) {
            $builder->where('canteen_id', $request['canteen_id']);
        }
        if (@$request['price']) {
            $builder->where('products.cost', $request['price']);
        }
        if (@$request['category_id']) {
            $builder->where('products.category_id', $request['category_id']);
        }
        if (!is_null($request['valid']  ?? null))
        {
            $builder->where('products.status', $request['valid']);
        }
        if (@$request['date_from']) {
            $builder->whereDate('products.created_at', '>=', $request['date_from']);
        }

        if (@$request['date_to']) {
            $builder->whereDate('products.created_at', '<=', $request['date_to']);
        }

        if (isset($request['status'])) {
            if (@$request['status'] == 0) {
                $builder->onlyTrashed();
            }
        }

        if (@$request['orderBy']) {
            $builder->orderBy($request['orderBy']['key'], $request['orderBy']['value']);
        } else {
            $builder->orderBy('id', 'DESC');
        }

        if (@$request['paginate'])
        {
            $products = $builder->paginate(50);
        }
        elseif (@$request['api'])
        {
            $products = $builder;
        } else
        {
            $products = $builder->cursor();
        }
        return $products;
    }


    public function getStock(array $request)
    {
        $builder = $this->productRepository->getStock($request);

        if (@$request['date'])
        {
            $builder->whereDate('date',$request['date']);
        }

        if (@$request['uuid'])
        {
            $builder->where('uuid',$request['uuid']);
        }


        if (@$request['category_id'])
        {
            $builder->where('category_id',$request['category_id']);
        }

        if (@$request['product_id'])
        {
            $builder->where('product_id',$request['product_id']);
        }

        if (@$request['start_date'])
        {
            $builder->where('date','>=',$request['start_date']);
        }

        if (@$request['end_date'])
        {
            $builder->where('date','<=',$request['end_date']);
        }

        if (@$request['canteen_id'])
        {
            $builder->where('canteen_id',$request['canteen_id']);
        }

        if (@$request['count'])
        {
            $builder->where('count',$request['count']);
        }

        if (@$request['price'])
        {
            $builder->where('price',$request['price']);
        }

        if (@$request['typeStatus'])
        {
            $builder->where('status',$request['typeStatus']);
        }

        if (@$request['product'])
        {
            $builder->whereHas('product.currentDescription',function ($query) use ($request){
                $query->where('title', 'LIKE', '%' . $request['product'] . '%');
            });
        }

        if (@$request['code'])
        {
            $builder->whereHas('product',function ($query) use ($request){
                $query->where('code',  $request['code'] );
            });
        }
        if (@$request['date_from']) {
            $builder->whereDate('products.created_at', '>=', $request['date_from']);
        }

        if (@$request['date_to']) {
            $builder->whereDate('products.created_at', '<=', $request['date_to']);
        }

        if (@$request['paginate'])
        {
            $stock = $builder->paginate(50);
        }
        elseif (@$request['api'])
        {
            $stock = $builder;
        }
        else
        {
            $stock = $builder->get();
        }

        return $stock;
    }
    public function getStockItem($id)
    {
        return $this->productRepository->getStockItem($id);
    }
    public function checkItem($id)
    {
        $product = $this->productRepository->checkItem($id);
        return $product;
    }

    public function getItem($id)
    {
        $product = $this->checkItem($id);
        $productDescription = $this->productRepository->getItem($id);
        foreach ($productDescription as $row) {
            $product[$row->local] = $row;
        }
        return $product;
    }

    public function getItemTrashed($id)
    {
        $product = $this->productRepository->getItemTrashed($id);
        return $product;
    }

    public function getItemByCode($code)
    {
        return $this->productRepository->getItemByCode($code);
    }

    public function generateCode()
    {
        do {
            $code = rand(100, 99999999999);
        } while (!is_null($this->getItemByCode($code)));
        return $code;
    }

    public function create(array $request): Product
    {
        $request['code'] = $this->generateCode();
        $product = $this->productRepository->create($request);
        $this->productRepository->saveData($request, $product->id);
        return $product;
    }
    public function update(array $request, int $id): Product
    {

        $product = $this->checkItem($id);
        $product = $this->productRepository->update($request, $product);
        $this->productRepository->saveData($request, $product->id);
        return $product;
    }
    public function updateMain(array $request, int $id): Product
    {

        $product = $this->checkItem($id);
        $product = $this->productRepository->update($request, $product);
        return $product;
    }

    public function createStock(array $request): ProductStock
    {
        $request['uuid'] = $this->UUID(50);
        $product = $this->getItem($request['product_id']);
        if ($product)
        {
            $request['original_count'] = $product->count;
            $request['original_price'] = $product->cost * $product->count;
        }
        else
        {
            $request['original_count'] = 0;
            $request['original_price'] = 0;
        }

        if ($request['status'] == ProductStockStatusEnum::PLUS->value)
        {
            $request['balance'] = $request['original_count'] + $request['count'];
            $request['balance_price'] = $request['original_price'] + $request['price'];
        }
        else
        {
            $request['balance'] = $request['original_count'] - $request['count'];
            $request['balance_price'] = $request['original_price'] - $request['price'];
        }

        return $this->productRepository->createStock($request);
    }

    public function UUID($length = 50)
    {
        $number = substr(str_shuffle(str_repeat(
            implode('', array_map('chr', array_merge(
                range(48, 57),
                range(65, 90),
                range(97, 122)
            ))), ceil($length / 62))),
            0, $length
        );

        if ($this->checkUUIDExists($number)) {
            return $this->UUID($length);
        }

        return $number;
    }
    public function checkUUIDExists($number)
    {
        return $this->productRepository->checkUUIDExists($number);
    }

    public function report(array $request)
    {
        if ($request['status'] == ReportEnum::StockLedger->value)
        {
            $report = $this->getStock($request);
            $reportClass = new StockLedgerExport($report);
            $name = 'stock_ledger';
        }
        elseif ($request['status'] == ReportEnum::StockBalance->value)
        {
            $report = $this->productRepository->StockBalance($request);
            $reportClass = new StocklBalanceExport($report);
            $name = 'stock_balance';
        }
        else
        {
            $report = $this->productRepository->ReportSales($request);
            $reportClass = new ReportSalesExport($report);
            $name = 'report_sales';
        }

        return [
            'reportClass'=> $reportClass,
            'name'=> $name
        ];
    }

    public function destroy(int $id): void
    {
        $product = $this->checkItem($id);
        if ($product) {
            $this->productRepository->destroy($product);
        } else {
            $product = $this->getItemTrashed($id);
            $this->productRepository->restore($product);
        }
    }
    public function destroyAll(array $request): void
    {
        if ($request['status'] == 1) {
            $this->productRepository->destroyAll($request['ids']);
        } else {
            $this->productRepository->restoreAll($request['ids']);
        }
    }
}
