<?php

namespace WT\ServiceBundle\Service;


use Doctrine\ORM\EntityManager;
use WT\CommonBundle\DateRange;
use WT\BackendBundle\Entity\Service\AccountSource;
use WT\ServiceBundle\AccountContextFactory;
use WT\ServiceBundle\Entity\Transaction;
use WT\ServiceBundle\Transactions\Collection\AbstractTransactionsCollection;
use WT\ServiceBundle\Transactions\Collection\TransactionsCollection;

class SourceUpdater
{


    private $entityManager;

    /**
     * @var SourceFactory
     */
    private $sourceFactory;

    /**
     * @var AccountContextFactory
     */
    private $accountContextFactory;

    public function __construct(EntityManager $em, SourceFactory $sourceFactory, AccountContextFactory $accountContextFactory)
    {
        $this->entityManager = $em;

        $this->sourceFactory = $sourceFactory;
        $this->accountContextFactory = $accountContextFactory;

    }

    /**
     * @param DateRange $range
     * @param AccountSource $accountSource
     * @return TransactionsCollection
     */
    private function loadTransactions(DateRange $range, AccountSource $accountSource)
    {
        $context = $this->accountContextFactory->getContext($accountSource->getAccount());
        $sourceObject = $this->sourceFactory->createSource($accountSource->getSourceType());

        $sourceParams = $accountSource->getParams();
        //$sourceParams = $this->container->get('wt.extractor_params')->extract($sourceParams);

        $transactions = $sourceObject->loadTransactions($range, $context, $sourceParams);
        foreach ($transactions as $transaction) {
            /** @var Transaction $transaction */
            $transaction->setSource($accountSource);
        }

        $this->accountContextFactory->saveContext($context);

        return $transactions;
    }

    public function updateTransactions(DateRange $range, AccountSource $accountSource)
    {
        $transactions = $this->loadTransactions($range, $accountSource);

        //dump($transactions);

        $sourceType = $accountSource->getSourceType();
        if ($sourceType->isStatistic()) {
            $updatedTransactions = $this->insertStatisticTransactions($transactions, $range, $accountSource);
        } else {
            $updatedTransactions = $this->insertTransactions($transactions, $range, $accountSource);
        }

        // set rules
        //dump($updatedTransactions);



    }


    private function mergeTransactions(TransactionsCollection $newTransactions, TransactionsCollection $oldTransactions)
    {
        $transactionsRepository = $this->entityManager->getRepository('WTServiceBundle:Transaction');

        $newKeys = $newTransactions->getKeys();
        $oldKeys = $oldTransactions->getKeys();

        // Insert
        $insertKeys = array_diff($newKeys, $oldKeys);
        $insertCollection = $newTransactions->extract($insertKeys);
        $transactionsRepository->insertCollection($insertCollection);

        // Update
        $updateKeys = array_intersect($newKeys, $oldKeys);
        foreach ($updateKeys as $key) {
            $oldItem = $oldTransactions->get($key);
            $newItem = $newTransactions->get($key);

            if ($oldItem->hash() != $newItem->hash()) {
                // update item
                $oldItem->load($newItem);
                $insertCollection->insert($oldItem);
            }
        }

        return $insertCollection;
    }


    private function insertTransactions(TransactionsCollection $newTransactions, DateRange $range, AccountSource $source)
    {
        $transactionsRepository = $this->entityManager->getRepository('WTServiceBundle:Transaction');
        $oldTransactions = $transactionsRepository->getBySource($source, $range, false);


        $insertCollection = $this->mergeTransactions($newTransactions, $oldTransactions);

        $newKeys = $newTransactions->getKeys();
        $oldKeys = $oldTransactions->getKeys();

        // Delete
        $deleteKeys = array_diff($oldKeys, $newKeys);
        foreach ($deleteKeys as $key) {
            $item = $oldTransactions->get($key);
            $this->entityManager->remove($item);
        }

        $this->entityManager->flush();

        return $insertCollection;
    }

    private function insertStatisticTransactions(TransactionsCollection $newTransactions, DateRange $range, AccountSource $source)
    {
        $transactionsRepository = $this->entityManager->getRepository('WTServiceBundle:Transaction');
        $oldTransactions = $transactionsRepository->getBySource($source, $range);

        $insertCollection = $this->mergeTransactions($newTransactions, $oldTransactions);

        $this->entityManager->flush();

        return $insertCollection;
    }


}