<?php
namespace Incoviba\Repository\Proyecto\Broker;

use Incoviba\Common;
use Incoviba\Repository;
use Incoviba\Model;

class Contract extends Common\Ideal\Repository
{
    public function __construct(Common\Define\Connection $connection, protected Repository\Proyecto\Broker $brokerRepository,
                                protected Repository\Proyecto $proyectoRepository)
    {
        parent::__construct($connection);
    }

    public function getTable(): string
    {
        return 'broker_contracts';
    }

    public function create(?array $data = null): Model\Proyecto\Broker\Contract
    {
        $map = (new Common\Implement\Repository\MapperParser(['commission']))
            ->register('broker_rut', (new Common\Implement\Repository\Mapper())
                ->setProperty('broker')
                ->setFunction(function($data) {
                    return $this->brokerRepository->fetchById($data['broker_rut']);
                })
            )
            ->register('project_id', (new Common\Implement\Repository\Mapper())
                ->setProperty('project')
                ->setFunction(function($data) {
                    return $this->proyectoRepository->fetchById($data['project_id']);
                })
            );
        return $this->parseData(new Model\Proyecto\Broker\Contract(), $data, $map);
    }
    public function save(Common\Define\Model $model): Model\Proyecto\Broker\Contract
    {
        $model->id = $this->saveNew(
            ['broker_rut', 'project_id', 'commission'],
            [$model->broker->rut, $model->project->id, $model->commission]);
        return $model;
    }

    /**
     * @param Common\Define\Model $model
     * @param array $new_data
     * @return Model\Proyecto\Broker\Contract
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function edit(Common\Define\Model $model, array $new_data): Model\Proyecto\Broker\Contract
    {
        return $this->update($model, ['broker_rut', 'project_id', 'commission'], $new_data);
    }

    /**
     * @param int $brokerRut
     * @return array
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function fetchByBroker(int $brokerRut): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select()
            ->from($this->getTable())
            ->where('broker_rut = :broker_rut');
        return $this->fetchMany($query, ['broker_rut' => $brokerRut]);
    }

    /**
     * @param int $projectId
     * @return array
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function fetchByProject(int $projectId): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select()
            ->from($this->getTable())
            ->where('project_id = :project_id');
        return $this->fetchMany($query, ['project_id' => $projectId]);
    }

    /**
     * @param int $brokerRut
     * @return array
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function fetchActiveByBroker(int $brokerRut): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select('a.*')
            ->from("{$this->getTable()} a")
            ->joined($this->statusJoin())
            ->where('a.broker_rut = :broker_rut AND bcs.state = :state');
        return $this->fetchMany($query, ['broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\Type::ACTIVE]);
    }

    /**
     * @param int $projectId
     * @return array
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function fetchActiveByProject(int $projectId): array
    {
        $query = $this->connection->getQueryBuilder()
            ->select('a.*')
            ->from("{$this->getTable()} a")
            ->joined($this->statusJoin())
            ->where('a.proyecto_id = :proyecto_id AND bcs.state = :state');
        return $this->fetchMany($query, ['proyecto_id' => $projectId, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]);
    }

    /**
     * @param int $projectId
     * @param int $brokerRut
     * @return Model\Proyecto\Broker\Contract
     * @throws Common\Implement\Exception\EmptyResult
     */
    public function fetchActiveByProjectAndBroker(int $projectId, int $brokerRut): Model\Proyecto\Broker\Contract
    {
        $query = $this->connection->getQueryBuilder()
            ->select('a.*')
            ->from("{$this->getTable()} a")
            ->joined($this->statusJoin())
            ->where('a.project_id = :project_id AND a.broker_rut = :broker_rut AND bcs.type = :state');
        return $this->fetchOne($query, ['project_id' => $projectId, 'broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]);
    }

    protected function statusJoin(): string
    {
        return 'INNER JOIN (SELECT bcs1.* FROM broker_contract_states bcs1 INNER JOIN (SELECT MAX(id) AS id, contract_id FROM broker_contract_states GROUP BY contract_id) bcs0 ON bcs0.id = bcs1.id) bcs ON bcs.contract_id = a.id';
    }
}
