<?php


namespace App\ViewModels\AgendaEspecialidade\AgendaEspecialidadeMultipleRegistrationViewModel;


use App\Utils\Builder;
use App\Utils\Collections\GeneralCollection;
use App\Utils\DateUtils;
use App\Utils\ResponseException;
use DateInterval;
use DateTime;

class AgendaEspecialidadeMultipleRegistrationViewModelBuilder implements Builder
{
    protected $id_medico;
    protected $id_unidade;
    protected $data_inicial;
    protected $data_final;
    protected $hora_inicio;
    protected $hora_fim;
    protected $id_especialidade;
    protected $encaixe;
    protected $tempo_atendimento;
    protected $dias_semana;
    protected $adicionado_por;


    /**
     * @param mixed $id_unidade
     * @return AgendaEspecialidadeMultipleRegistrationViewModelBuilder
     */
    public function setIdUnidade($id_unidade)
    {
        $this->id_unidade = $id_unidade;
        return $this;
    }

    public function setIdMedico(int $id_medico): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $this->id_medico = $id_medico;
        return $this;
    }

    public function setDataInicial(DateTime $data_inicial): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $this->data_inicial = $data_inicial;
        return $this;
    }

    public function setDataFinal(DateTime $data_final): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        if ($this->data_inicial->diff($data_final)->days > TEMPO_MAXIMO_GERACAO_AGENDA) {
            throw new ResponseException(['data_final' => 'O tempo máximo para geração de agenda é de ' . TEMPO_MAXIMO_GERACAO_AGENDA . ' dias.'], 'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder');
        }
        if (DateUtils::datetime_to_date($data_final) > DateUtils::datetime_to_date($this->data_inicial)) {
            $this->data_final = $data_final;
            return $this;
        } else {
            throw new ResponseException(['data_final' => 'A data final deve ser maior que a data inicial.'], 'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder');
        }
    }

    public function setHoraInicio(DateTime $hora_inicio): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $this->hora_inicio = $hora_inicio;
        return $this;
    }

    public function setHoraFim(DateTime $hora_fim): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        if (DateUtils::datetime_to_time($hora_fim) > DateUtils::datetime_to_time($this->hora_inicio)) {
            $this->hora_fim = $hora_fim;
            return $this;
        } else {
            throw new ResponseException(['hora_fim' => 'A hora final deve ser maior que a hora inicial.'], 'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder');
        }
    }

    public function setTempoAtendimento(DateInterval $tempo_atendimento): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $initial_schedule = DateUtils::getDateTime($this->hora_inicio);
        $minutes = DateUtils::dateIntervalMinutes($tempo_atendimento);
        $time_next_schedule = strtotime("+ {$minutes} minute", $initial_schedule->getTimestamp());
        $final_schedule_calculated_by_interval = new DateTime(date('H:i', $time_next_schedule));
        if ($minutes < TEMPO_MINIMO_CONSULTA) {
            throw new ResponseException(
                ['tempo_atendimento' => 'O tempo de consulta deve ser, no mínimo, ' . TEMPO_MINIMO_CONSULTA . ' minutos.'],
                'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder'
            );
        }
        if (
            DateUtils::datetime_to_time($final_schedule_calculated_by_interval) <= DateUtils::datetime_to_time($this->hora_fim) &&
            DateUtils::datetime_to_time($final_schedule_calculated_by_interval) >  DateUtils::datetime_to_time($initial_schedule)
        ) {
            $this->tempo_atendimento = $tempo_atendimento;
            return $this;
        } else {
            throw new ResponseException(
                ['tempo_atendimento' => 'O tempo de consulta deve poder ser contido entre a hora inicial e final determinadas em sua solicitação.'],
                'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder'
            );
        }
    }

    public function setDiasSemana(GeneralCollection $dias_semana): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $is_valid = $dias_semana->length === 7 && $dias_semana->every(function ($element) {
            return $element === 1 or $element === 0;
        });
        if ($is_valid) {
            $this->dias_semana = $dias_semana;
            return $this;
        } else {
            throw new ResponseException(['dias_semana' => 'Dado fora do formato esperado.'], 'Erro na construção do objeto AgendaEspecialidadeMultipleRegistrationViewModelBuilder');
        }
    }

    public function setAdicionadoPor(int $adicionado_por): AgendaEspecialidadeMultipleRegistrationViewModelBuilder
    {
        $this->adicionado_por = $adicionado_por;
        return $this;
    }

    public function setIdEspecialidade($id_especialidade)
    {
        $this->id_especialidade = $id_especialidade;
        return $this;
    }

    /**
     * @param mixed $encaixe
     * @return AgendaEspecialidadeMultipleRegistrationViewModelBuilder
     */
    public function setEncaixe($encaixe)
    {
        $this->encaixe = $encaixe;
        return $this;
    }

    public function build() : AgendaEspecialidadeMultipleRegistrationViewModel
    {
        $agenda_multiple_registration_vm = new AgendaEspecialidadeMultipleRegistrationViewModel();
        $agenda_multiple_registration_vm->setidmedico($this->id_medico);
        $agenda_multiple_registration_vm->setIdUnidade($this->id_unidade);
        $agenda_multiple_registration_vm->setdatainicial($this->data_inicial);
        $agenda_multiple_registration_vm->setdatafinal($this->data_final);
        $agenda_multiple_registration_vm->sethorainicio($this->hora_inicio);
        $agenda_multiple_registration_vm->sethorafim($this->hora_fim);
        $agenda_multiple_registration_vm->settempoatendimento($this->tempo_atendimento);
        $agenda_multiple_registration_vm->setdiassemana($this->dias_semana);
        $agenda_multiple_registration_vm->setadicionadopor($this->adicionado_por);
        $agenda_multiple_registration_vm->setIdEspecialidade($this->id_especialidade);
        $agenda_multiple_registration_vm->setEncaixe($this->encaixe);
        return $agenda_multiple_registration_vm;
    }


}