<?php

use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;

/* @bundles/LeadBundle/Segment/Stat/ChartQuery/SegmentContactsLineChartQuery.php */
class __TwigTemplate_9c0f935076a6702864e0ab03233dced2 extends Template
{
    private $source;
    private $macros = [];

    public function __construct(Environment $env)
    {
        parent::__construct($env);

        $this->source = $this->getSourceContext();

        $this->parent = false;

        $this->blocks = [
        ];
    }

    protected function doDisplay(array $context, array $blocks = [])
    {
        $macros = $this->macros;
        // line 1
        echo "<?php

namespace Mautic\\LeadBundle\\Segment\\Stat\\ChartQuery;

use Doctrine\\DBAL\\Connection;
use Doctrine\\DBAL\\Query\\Expression\\CompositeExpression;
use Doctrine\\DBAL\\Query\\QueryBuilder;
use Mautic\\CoreBundle\\Helper\\ArrayHelper;
use Mautic\\CoreBundle\\Helper\\Chart\\ChartQuery;
use Mautic\\LeadBundle\\Entity\\LeadEventLog;
use Mautic\\LeadBundle\\Entity\\ListLead;
use Mautic\\LeadBundle\\Segment\\Exception\\SegmentNotFoundException;

class SegmentContactsLineChartQuery extends ChartQuery
{
    /**
     * @var array
     */
    private \$filters;

    /**
     * @var int
     */
    private \$segmentId;

    /**
     * @var bool|string
     */
    private \$firstEventLog;

    /**
     * @var array
     */
    private \$addedEventLogStats;

    /**
     * @var array
     */
    private \$removedEventLogStats;

    /**
     * @var array
     */
    private \$addedLeadListStats;

    /**
     * @var bool
     */
    private \$statsFromEventLog;

    /**
     * @param string|null \$unit
     *
     * @throws SegmentNotFoundException
     */
    public function __construct(Connection \$connection, \\DateTime \$dateFrom, \\DateTime \$dateTo, array \$filters = [], \$unit = null)
    {
        \$this->connection = \$connection;
        \$this->dateFrom   = \$dateFrom;
        \$this->dateTo     = \$dateTo;
        \$this->unit       = \$unit;
        \$this->filters    = \$filters;

        if (!isset(\$this->filters['leadlist_id']['value'])) {
            throw new SegmentNotFoundException('Segment ID required');
        }
        \$this->segmentId  = \$this->filters['leadlist_id']['value'];
        parent::__construct(\$connection, \$dateFrom, \$dateTo, \$unit);
    }

    public function setDateRange(\\DateTime \$dateFrom, \\DateTime \$dateTo)
    {
        parent::setDateRange(\$dateFrom, \$dateTo);
        \$this->init();
    }

    /**
     * @return array
     */
    public function getTotalStats(int \$total)
    {
        \$totalCountDateTo = \$this->getTotalToDateRange(\$total);
        // count array SUM and then reverse
        // require start from end and  substract added/removed logs
        \$sums     = array_reverse(ArrayHelper::sub(\$this->getAddedEventLogStats(), \$this->getRemovedEventLogStats()));
        \$totalSum = 0;
        \$totals   = array_map(function (\$sum) use (\$totalCountDateTo, &\$totalSum) {
            \$total = \$totalCountDateTo - \$totalSum;
            \$totalSum += \$sum;
            if (\$total > -1) {
                return \$total;
            } else {
                return 0;
            }
        }, \$sums);

        return array_reverse(\$totals);
    }

    /**
     * Return total of contact to date end of graph.
     */
    private function getTotalToDateRange(int \$total): int
    {
        \$queryForTotal = clone \$this;
        // try figure out total count in dateTo
        \$queryForTotal->setDateRange(\$this->dateTo, new \\DateTime());

        return \$total - array_sum(ArrayHelper::sub(\$queryForTotal->getAddedEventLogStats(), \$queryForTotal->getRemovedEventLogStats()));
    }

    /**
     * Get data about add/remove from segment based on LeadEventLog.
     *
     * @param string \$action
     *
     * @return array
     */
    public function getDataFromLeadEventLog(\$action)
    {
        \$qb = \$this->prepareTimeDataQuery(
            'lead_event_log',
            'date_added',
            [
                'object'    => 'segment',
                'bundle'    => 'lead',
                'action'    => \$action,
                'object_id' => \$this->segmentId,
            ]
        );
        \$qb = \$this->optimizeSearchInLeadEventLog(\$qb);

        return \$this->loadAndBuildTimeData(\$qb);
    }

    /**
     * Get data about add from segment based on LeadListLead before upgrade to 2.15.
     *
     * @return array
     */
    public function getDataFromLeadListLeads()
    {
        \$q = \$this->prepareTimeDataQuery('lead_lists_leads', 'date_added', \$this->filters);
        if (\$this->firstEventLog) {
            \$q->andWhere(\$q->expr()->lt('t.date_added', \$q->expr()->literal(\$this->firstEventLog)));
        }
        \$q = \$this->optimizeListLeadQuery(\$q);

        return \$this->loadAndBuildTimeData(\$q);
    }

    /**
     * @return bool|string
     */
    private function getFirstDateAddedSegmentEventLog()
    {
        \$subQuery = \$this->connection->createQueryBuilder();
        \$subQuery->select('el.date_added - INTERVAL 10 SECOND')
            ->from(MAUTIC_TABLE_PREFIX.'lead_event_log', 'el')
            ->where(
                \$subQuery->expr()->andX(
                    \$subQuery->expr()->eq('el.object', \$subQuery->expr()->literal('segment')),
                    \$subQuery->expr()->eq('el.bundle', \$subQuery->expr()->literal('lead')),
                    \$subQuery->expr()->eq('el.object_id', \$this->segmentId)
                )
            )
            ->orderBy('el.date_added')
            ->setFirstResult(0)
            ->setMaxResults(1);

        return \$subQuery->execute()->fetchColumn();
    }

    /**
     * @return int
     */
    public function getSegmentId()
    {
        return \$this->segmentId;
    }

    /**
     * @return bool
     */
    public function isStatsFromEventLog()
    {
        return \$this->statsFromEventLog;
    }

    /**
     * @return array
     */
    public function getAddedEventLogStats()
    {
        return \$this->addedEventLogStats;
    }

    /**
     * @return array
     */
    public function getRemovedEventLogStats()
    {
        return \$this->removedEventLogStats;
    }

    /**
     * Init basic stats.
     */
    private function init(): void
    {
        \$this->firstEventLog        = \$this->getFirstDateAddedSegmentEventLog();
        \$this->addedLeadListStats   = \$this->getDataFromLeadListLeads();
        \$this->addedEventLogStats   = \$this->getDataFromLeadEventLog('added');
        \$this->removedEventLogStats = \$this->getDataFromLeadEventLog('removed');
        \$this->statsFromEventLog    = (
            empty(array_filter(\$this->addedLeadListStats))
            && (!empty(array_filter(\$this->addedEventLogStats))
            || !empty(array_filter(\$this->removedEventLogStats)))
        );
    }

    private function optimizeListLeadQuery(QueryBuilder \$qb): QueryBuilder
    {
        if (
            // Remove unwanted self join with lead_lists_leads table
            false !== (\$key = array_search(MAUTIC_TABLE_PREFIX.ListLead::TABLE_NAME, array_column(\$qb->getQueryPart('from'), 'table'))) &&
            false !== (\$joinKey = array_search(MAUTIC_TABLE_PREFIX.ListLead::TABLE_NAME, array_column(\$qb->getQueryPart('join')[\$tableAlias = \$qb->getQueryPart('from')[\$key]['alias']], 'joinTable')))
        ) {
            \$joinAlias = \$qb->getQueryPart('join')[\$tableAlias][\$joinKey]['joinAlias'];
            \$qb->resetQueryPart('join');
            \$compositeExpression = \$qb->getQueryPart('where');
            \$this->removeUnwantedWhereClause(\$compositeExpression, \$joinAlias);
        }

        return \$qb;
    }

    private function removeUnwantedWhereClause(CompositeExpression \$compositeExpression, string \$joinAlias): void
    {
        // CompositeExpression class has no way to remove members of it's 'parts' property, and we have
        // to resort on Reflection here.
        \$compositeExpressionReflection      = new \\ReflectionClass(CompositeExpression::class);
        \$compositeExpressionReflectionParts = \$compositeExpressionReflection->getProperty('parts');
        \$compositeExpressionReflectionParts->setAccessible(true);
        \$parts    = \$compositeExpressionReflectionParts->getValue(\$compositeExpression);
        \$newParts = array_filter(\$parts, function (\$val) use (\$joinAlias) {
            return 0 !== strpos(\$val, \"\$joinAlias.\");
        });
        \$compositeExpressionReflectionParts->setValue(\$compositeExpression, \$newParts);
        \$compositeExpressionReflectionParts->setAccessible(false);
    }

    private function optimizeSearchInLeadEventLog(QueryBuilder \$qb): QueryBuilder
    {
        \$fromPart             = \$qb->getQueryPart('from');
        \$fromPart[0]['alias'] = sprintf('%s USE INDEX (%s)', \$fromPart[0]['alias'], MAUTIC_TABLE_PREFIX.LeadEventLog::INDEX_SEARCH);
        \$qb->resetQueryPart('from');
        \$qb->from(\$fromPart[0]['table'], \$fromPart[0]['alias']);

        return \$qb;
    }
}
";
    }

    public function getTemplateName()
    {
        return "@bundles/LeadBundle/Segment/Stat/ChartQuery/SegmentContactsLineChartQuery.php";
    }

    public function getDebugInfo()
    {
        return array (  37 => 1,);
    }

    public function getSourceContext()
    {
        return new Source("", "@bundles/LeadBundle/Segment/Stat/ChartQuery/SegmentContactsLineChartQuery.php", "/var/www/mautic/app/bundles/LeadBundle/Segment/Stat/ChartQuery/SegmentContactsLineChartQuery.php");
    }
}
