<?php

namespace App\Services;

use App\Enums\StatusAgendamentoAtendimentoEnum;
use App\Enums\TipoAgendamentoEnum;
use App\Exceptions\HorarioIndisponivelFeriadoException;
use App\Exceptions\HorarioIndisponivelForaHorarioServicoException;
use App\Exceptions\HorarioIndisponivelSobrepoeHorarioJuridicoException;
use App\Exceptions\ServicoAtendimentoSemHorariosDefinidosException;
use App\Models\AgendamentoAtendimento;
use App\Models\Feriado;
use App\Models\ServicoAtendimento;
use Carbon\Carbon;

class AgendaAtendimentoJuridicoService extends AgendaAtendimentoService
{
    protected $inicio;
    protected $fim;
    protected $servicoAtendimento;
    protected $tipo;
    protected $extraordinario;
    protected $motivoExtraordinario;
    protected $permiteAgendamentoProximo;

    public function __construct(Carbon $inicio, Carbon $fim, $pessoa, ServicoAtendimento $servicoAtendimento, $extraordinario = false, $motivoExtraordinario = '', $permiteAgendamentoProximo = false)
    {
        parent::__construct($inicio, $fim, $pessoa, TipoAgendamentoEnum::juridico());
        
        $this->servicoAtendimento = $servicoAtendimento;
        $this->extraordinario = $extraordinario;
        $this->motivoExtraordinario = $motivoExtraordinario;
        $this->permiteAgendamentoProximo = $permiteAgendamentoProximo;
    }

    public function agenda()
    {
        $agendamento = new AgendamentoAtendimento();
        $agendamento->inicio = $this->inicio;
        $agendamento->fim = $this->fim;
        $agendamento->servicoAtendimento()->associate($this->servicoAtendimento);
        $agendamento->agendavel()->associate($this->pessoa);
        $agendamento->tipo = strtolower($this->tipo->getName());
        $agendamento->status = StatusAgendamentoAtendimentoEnum::aberto();

        $this->verificaDisponibilidade();
        $this->verificaSeHaAgendamentoProximo();
        
        $agendamento->extraordinario = $this->extraordinario;
        $agendamento->motivo_extraordinario = $this->motivoExtraordinario;
        $agendamento->save();
        
        return $agendamento;
    }

    public function verificaDisponibilidade()
    {
        if (Feriado::eFeriado($this->inicio, $this->fim)) {
            throw new HorarioIndisponivelFeriadoException($this->inicio, $this->fim);
        }

        if (!$this->dentroHorarioServicoAtendimento()) {
            throw new HorarioIndisponivelForaHorarioServicoException($this->inicio, $this->fim);
        }

        if ($this->sobrepoeHorario()) {
            $agendamentoSobreposto = $this->agendamentoSobreposto();

            if (! $this->extraordinario) {
                throw new HorarioIndisponivelSobrepoeHorarioJuridicoException($this->inicio, $this->fim, $agendamentoSobreposto);
            }
        }
    }

    public function dentroHorarioServicoAtendimento()
    {
        $horarios = $this->servicoAtendimento->horariosTrabalho;

        if ($horarios->isEmpty()) {
            throw new ServicoAtendimentoSemHorariosDefinidosException($this->servicoAtendimento);
        }

        $diaSemana = $this->diaSemana($this->inicio);

        return $this->servicoAtendimento->horariosTrabalho()
            ->where('dia_semana', 'ilike', $diaSemana->getName())
            ->where('inicio', '<=', $this->inicio)
            ->where('fim', '>=', $this->fim)
            ->get()
            ->isNotEmpty();
    }
}
