<?php

namespace Win7\Ads\Repository;

use Win7\Ads\Entity\CustomerFilter;
use Win7\Ads\Exception\RuntimeException;
use Win7\Ads\Report\QueryBuilder;
use Win7\Ads\Report\ReportRequest;
use Win7\Ads\Service\RequestManager;

/**
 * Representa um repositório responsável por consultas e administração de recursos do ads.
 *
 * @author Thiago Daher
 */
abstract class AdsRepository
{

    /**
     * @var \Win7\Ads\Service\RequestManager
     */
    private $manager;

    /**
     * @var string
     */
    private $customerId;

    /**
     * @param \Win7\Ads\Service\RequestManager $manager
     */
    public function __construct(RequestManager $manager)
    {
        $this->manager = $manager;
    }

    /**
     * @return string
     */
    public function getCustomerId(): string
    {
        return $this->customerId;
    }

    /**
     * @param string $customerId
     */
    public function setCustomerId(string $customerId): void
    {
        $this->customerId = $customerId;
    }

    /**
     * Realiza a consulta do relatório e retorna o resultado.
     *
     * @param \Win7\Ads\Report\ReportRequest $request
     * @return array
     */
    protected function getReportResult(ReportRequest $request): array
    {
        if (!$request->isValid()) {
            throw new RuntimeException('Invalid request');
        }

        $params = [
            'json' => [
                'query' => $request->getQueryBuilder()->asString(),
            ],
        ];

        $result = $this->manager->sendPost(
            'customers/' . $request->getCustomerId() . '/googleAds:searchStream',
            $params
        );

        if ($result->getStatusCode() < 200 || $result->getStatusCode() >= 300) {
            throw new RuntimeException('Request error. Details: ' . $result->getBody());
        }

        $result = json_decode((string)$result->getBody(), true);

        return $result[0]['results'] ?? [];
    }

    /**
     * Realiza alguma alteração de recursos no ads (inserção, atualização e remoção).
     *
     * @param string $resourceType tipo do recurso
     * @param string $customerId ID do cliente
     * @param array $operations operações que serão realizadas
     * @return void
     */
    protected function mutate(string $resourceType, string $customerId, array $operations)
    {
        $params = [
            'json' => [
                'customer_id' => $customerId,
                'operations'  => $operations,
            ],
        ];

        $result = $this->manager->sendPost(
            'customers/' . $customerId . '/' . $resourceType . ':mutate',
            $params
        );

        if ($result->getStatusCode() < 200 || $result->getStatusCode() >= 300) {
            throw new RuntimeException('Request error. Details: ' . $result->getBody());
        }
    }

    /**
     * Aplica os filtros de data.
     *
     * @param \Win7\Ads\Report\QueryBuilder $qb
     * @param \Win7\Ads\Entity\CustomerFilter $filter
     * @return void
     */
    protected function applyDateFilter(QueryBuilder $qb, CustomerFilter $filter)
    {
        if ($filter->getDateFilter() === 'ALL_TIME') {
            return;
        }

        if ($filter->getDateFilter() === 'CUSTOM_DATE') {
            $qb->andWhere("segments.date >= '" . $filter->getStartDate() . "'");
            $qb->andWhere("segments.date <= '" . $filter->getEndDate() . "'");

            return;
        }

        $qb->andWhere('segments.date DURING ' . $filter->getDateFilter());
    }

    /**
     * Aplica as configurações de filtragem da campanha.
     *
     * @param \Win7\Ads\Report\QueryBuilder $qb
     * @param \Win7\Ads\Entity\CustomerFilter $filter
     * @param bool $applySearch
     * @return void
     */
    protected function applyCampaignFilter(QueryBuilder $qb, CustomerFilter $filter, bool $applySearch = true)
    {
        if ($filter->isShowOnlySearch() && $applySearch) {
            $qb->andSelect('segments.ad_network_type');
            $qb->andWhere("segments.ad_network_type = 'SEARCH'");
        }

        switch ($filter->getCampaignMode()) {
            case CustomerFilter::MODE_SHOW_ONLY_CAMPAIGNS:
                $qb->andWhere($qb->expr()->in('campaign.id', $filter->getCampaignIds()));
                break;
            case CustomerFilter::MODE_SHOW_ALL_EXCEPT_CAMPAIGNS:
                $qb->andWhere($qb->expr()->notIn('campaign.id', $filter->getCampaignIds()));
                break;
        }
    }
}
