<?php

namespace App\Helper;


use App\Entity\Product;
use App\Entity\Stock;
use App\Entity\Warehouse;
use App\Repository\ProductRepository;
use App\Repository\StockRepository;
use App\Repository\WarehouseRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\Finder\Finder;


class HiltesImport
{
    private $productRepository;
	private $stockRepository;
    private $warehouseRepository;
    private $logger;
	protected $currentDirPath;
	protected $cachedWarehouseIds;
	private $cachedProdIds;
	private $cachedStockIds;
	protected $arrData = array();

	public function __construct(ProductRepository $productRepository,WarehouseRepository $warehouseRepository,StockRepository $stockRepository, LoggerInterface $logger)
	{
        $this->productRepository = $productRepository;
        $this->warehouseRepository = $warehouseRepository;
		$this->stockRepository = $stockRepository;
        $this->logger = $logger;

		$this->currentDirPath = getcwd();
	}


    /**
     * @return array|void
     */
	public function startImport($delta = false)
	{
		#*** Holt alle Dateien
		if($this->getFiles($delta)){
			#*** Holt alle Stocks und setzt ein Array **************
			$this->getStocks();
            $count = 0;
			if(!empty($this->arrData['orgFiles']['data']) && count($this->arrData['orgFiles']['data'])){
				foreach ($this->arrData['orgFiles']['data'] as $file) {

					if(is_file($file['realPath'])){
						$count += $this->loadFiles($file['realPath']);
					}else{
                        throw new \RuntimeException("Error: File not found - " . $file['realPath']);
                    }
                }

                $this->logger->info("Imported $count stocks");
            } else {
                $this->logger->info('No Files');
					}
        } else {
            throw new \RuntimeException('Error in getFiles or no file WS.FERTIG');
        }
	}

    /**
     * @return bool
     */
	protected function getFiles($delta = false)
	{
		$finder = Finder::create();
		$finder
			->in($this->currentDirPath.'/hiltes/h2c/')
			->depth(0);

        if($delta) {
            $finder->name('/_D/');
        }else{
            $finder->notName('/_D/');
        }

		if ($finder->hasResults()) {
			foreach ($finder as $file) {
                if($file->getExtension() != 'Ende') {
                    //prüfen ob Ende Datei vorhanden ist
                    if(file_exists($this->currentDirPath.'/hiltes/h2c/'.$file->getRelativePathname().'.Ende')) {
                        $this->arrData['orgFiles']['data'][] = array(
                            'realPath'	=> $file->getRealPath(),
                            'fileSize'	=> $file->getFileInfo()->getSize(),
                            'onlyFileName'	=> $file->getRelativePathname(),
                        );
                    }
                }
			}
		}else{
			return false;
		}

        return true;
	}
	protected function getStocks()
	{
        $stocks = $this->stockRepository->findAll();

        foreach ($stocks as $stock) {
            $this->cachedStockIds[$stock->getProductId()][$stock->getWarehouse()->getId()] = $stock;
		}
	}

	protected function loadFiles($srcFile)
	{
        try {
            $file = new \SplFileObject($srcFile);
            $this->logger->info('Starte Import von ' . $file->getRealPath());
            $count = 0;

            while (!$file->eof()) {
                $this->processLine($file->fgets());
                $count++;
		    }
        }catch (\Exception $e) {
            $this->logger->error($e->getMessage());
        }

        unlink($srcFile);
        unlink($srcFile . '.Ende');

        $this->logger->info($count . ' Datensätze importiert');

        return $count;
	}

    protected function processLine($line)
    {
        $data = str_getcsv($line, ';', '"');

        if (!empty($data[0])) {
            $this->trimArray($data);
            $this->saveData($data);
		}
	}

    protected function trimArray(array &$arr)
    {
		foreach ($arr as $k=>$v) {
			$arr[$k] = trim($v);
		}
	}

    protected function saveData(array $data)
    {
        $warehouse = $this->checkWarehouseName($data[3]);
        $gtin = $this->checkProduct(substr($data[0], 1));

        if (!empty($warehouse) && !empty($this->cachedStockIds[$gtin][$warehouse->getId()])) {
            $stock = $this->cachedStockIds[$gtin][$warehouse->getId()];
		}else{
        	$stock = new Stock();
	        $stock->setProductId($gtin);
            $stock->setWarehouse($warehouse);
		}

        $stock->setInstock((int) $data[1] / 100);
		$this->stockRepository->save($stock,true);
	}

    private function checkWarehouseName(string $warehouseName)
    {
        $warehouseName = ltrim($warehouseName, 0);

        if (empty($this->cachedWarehouseIds[$warehouseName])) {
            $warehouse = $this->warehouseRepository->findOneBy(['id' => (int) $warehouseName]);

            if (empty($warehouse)) {
				$warehouse = new Warehouse();
                $warehouse->setId((int) $warehouseName);
                $warehouse->setName($warehouseName);
                $this->warehouseRepository->save($warehouse,true);
                $this->cachedWarehouseIds[$warehouseName] = $warehouse;
			}else{
                $this->cachedWarehouseIds[$warehouseName] = $warehouse;
            }
            }

        if (!empty($this->cachedWarehouseIds[$warehouseName])) {
            return $this->cachedWarehouseIds[$warehouseName];
		}

		return false;
	}

    /**
     * @param string $gtin
     * @return false|int|mixed|null
     */
	private function checkProduct(string $gtin){
		#*** WEnn keine geCached Id Vorhanden
		if(empty($this->cachedProdIds[$gtin])){
            $product = $this->productRepository->findOneBy(['gtin' => $gtin]);

            if (empty($product)) {
                $product = new Product();
                $product->setGtin($gtin);
                $this->cachedProdIds[$gtin] = $this->productRepository->save($product, true);
			}else{
                $this->cachedProdIds[$gtin] = $product->getId();
            }
            }

        if (!empty($this->cachedProdIds[$gtin])) {
			return $this->cachedProdIds[$gtin];
        }

		return false;
	}
}