<?php

namespace App\Jobs;

use App\Mail\AlerteProjet;
use App\Models\Alerte;
use App\Models\AlerteEnvoyee;
use App\Models\Projet;
use App\Notifications\AlerteNotification;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use TEXT;

class EnvoyerAlerte implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 5;

    protected $_projet;
    protected $_structure_id;

    /**
     * Create a new job instance.
     *
     * @param Projet $projet
     * @param int $structure_id
     */
    public function __construct(Projet $projet, int $structure_id)
    {
        $this->_projet = $projet;
        $this->_structure_id = $structure_id;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // On récupère toutes les alertes de la structure
        $alertes = Alerte::select('alertes.*')
            ->join('users', 'users.id', '=', 'alertes.user_id')
            ->where('users.structure_id', $this->_structure_id)->get();

        foreach ($alertes as $a) {
            switch ($a->critere) {
                case TEXT::MONTANT_REFERENCE:
                    $this->process($a, 'montant de référence', $this->_projet->montant_reference, '€');
                    break;
                case TEXT::GAINS_SECURISES:
                    $this->process($a, 'gains sécurisé', $this->_projet->gains_securise, '€');
                    break;
                case TEXT::GAINS_NOTIFIES:
                    $this->process($a, 'gains notifié', round((($this->_projet->montant_reference - $this->_projet->montant_notifie) / $this->_projet->montant_reference) * 100, 0), '%');
                    break;
                case TEXT::MONTANT_NOTIFIE:
                    $this->process($a, 'montant notifié', $this->_projet->montant_notifie, '€');
                    break;
                case TEXT::GAINS_CIBLE:
                    $this->process($a, 'gains cible', $this->_projet->pourcentage_gains_cible, '%');
                    break;
            }
        }
    }

    /**
     * Permet de vérifier si une alerte est levée ou non
     * Envoi ensuite une alerte si cette dernière est vérifiée
     * @param $alerte
     * @param $critere
     * @param $valeur
     */
    private function process($alerte, $critere, $valeur, $symbole)
    {
        if ($valeur != null) {
            $indicateur = $alerte->est_valeur ? $alerte->indicateur : $this->get_project_value($alerte->indicateur_critere);
            if ($this->check_alerte($indicateur, $alerte->formule, $valeur)) {
                // On save l'alerte en BDD
                AlerteEnvoyee::create([
                    'indicateur' => $valeur,
                    'send_to' => $alerte->user->email,
                    'alerte_id' => $alerte->id,
                    'projet_id' => $this->_projet->id
                ]);

                $this->envoyer_alerte(
                    $alerte->user,
                    $this->_projet->objet,
                    $critere,
                    $alerte->formule,
                    $alerte->est_valeur,
                    $alerte->indicateur,
                    $alerte->indicateur_critere,
                    $valeur,
                    $this->_projet->id,
                    $symbole
                );
            }
        }
    }

    /**
     * Permet de vérifier si la condition d'une alerte est vérifiée ou non
     * @param $indicateur
     * @param $formule
     * @param $valeur
     * @return bool
     */
    private function check_alerte($indicateur, $formule, $valeur)
    {
        switch ($formule) {
            case '<':
                return $valeur < $indicateur;
            case '>':
                return $valeur > $indicateur;
            case '=':
                return $valeur == $indicateur;
            case '<=':
                return $valeur <= $indicateur;
            case '>=':
                return $valeur >= $indicateur;
            default:
                return false;
        }
    }

    /**
     * Permet d'envoyer un mail d'alerte une fois la condition remplie
     * @param $user
     * @param $objet
     * @param $critere
     * @param $formule
     * @param $est_valeur
     * @param $indicateur
     * @param $valeur
     * @param $projet_id
     */
    private function envoyer_alerte($user, $objet, $critere, $formule, $est_valeur, $indicateur, $indicateur_critere, $valeur, $projet_id, $symbole)
    {
        Mail::to($user->email)->send(new AlerteProjet(
            $objet,
            $critere,
            $formule,
            $est_valeur,
            $indicateur,
            $indicateur_critere,
            $valeur,
            $projet_id,
            $symbole
        ));

        // On envoie également une notification lorsqu'une alerte est envoyée
        $message = 'Alerte déclenchée sur le projet "' . $objet . '".';
        $message .= $est_valeur ? ' Le critère est "' . $critere . ' ' . $formule . ' ' . $indicateur . ' ' . $symbole . '".' : ' Le critère est "' . $critere . ' ' . $formule . ' ' . TEXT::FORMATTED_TEXT[$indicateur_critere] . '".';
        $message .= $est_valeur ? ' La valeur atteinte est "' . $valeur . ' ' . $symbole . '".' : '';
        $user->notify(new AlerteNotification($message, $projet_id));
    }

    private function get_project_value($indicateur_critere)
    {
        switch ($indicateur_critere) {
            case TEXT::GAINS_SECURISES:
                return $this->_projet->gains_securise;
            case TEXT::MONTANT_REFERENCE:
                return $this->_projet->montant_reference;
            case TEXT::GAINS_NOTIFIES:
                return round((($this->_projet->montant_reference - $this->_projet->montant_notifie) / $this->_projet->montant_reference) * 100, 0);
            case TEXT::MONTANT_NOTIFIE:
                return $this->_projet->montant_notifie;
            case TEXT::GAINS_CIBLE:
                return $this->_projet->pourcentage_gains_cible;
        }
    }
}
