<?php

namespace App\Http\Controllers\Projets;

use App\Exports\ProjetsExport;
use App\Http\Controllers\Controller;
use App\Http\Requests\Projets\UpdateProjetAchatComplexe;
use App\Http\Requests\Projets\UpdateProjetAchatComplexeDgos;
use App\Http\Requests\Projets\UpdateProjetAchatInvestissement;
use App\Http\Requests\Projets\UpdateProjetAchatSimple;
use App\Http\Requests\Projets\UpdateProjetSuivi;
use App\Jobs\EnvoyerAlerte;
use App\Models\AchatComplexeProjet;
use App\Models\Action;
use App\Models\ActionUniteOeuvre;
use App\Models\Categorie;
use App\Models\Direction;
use App\Models\Domaine;
use App\Models\EtapeProjet;
use App\Models\Famille;
use App\Models\GainAchatComplexeProjet;
use App\Models\ImputationBudgetaire;
use App\Models\MembreProjet;
use App\Models\NiveauMutualisation;
use App\Models\OperateurMutualisation;
use App\Models\Paat;
use App\Models\Projet;
use App\Models\ProjetActionRespSocEnv;
use App\Models\Segment;
use App\Models\Structure;
use App\Models\Thematique;
use App\Models\User;
use APPLICATION;
use ETAPE_PROJET;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use App\Models\Levier;
use App\Models\MontantAchatComplexeProjet;
use App\Models\PortefeuilleAcheteur;
use App\Models\ProjetStatut;
use App\Models\Service;
use App\Models\Statut;
use App\Notifications\AlerteNotification;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Maatwebsite\Excel\Facades\Excel;
use PAAT_STATUT;
use PROJET_STATUT;
use TYPE_CALCUL_GAINS;
use ROLE;

class ProjetController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:see_projet')->only(['index', 'filtres']);
        $this->middleware('permission:add_projet')->only(['create', 'store']);
        $this->middleware('permission:edit_projet')->only([
            'edit', 'update', 'ajouter_membre', 'supprimer_membre', 'update_resp_soc_env',
            'update_suivi', 'update_statuts', 'recherche', 'update_achats_simples', 'update_achats_complexes',
            'envoyer_notification', 'supprimer_fichier'
        ]);
        // Permessions spécifiques pour l'update du statut
        $this->middleware('permission:suspendre_acheteur|abandonner_acheteur|soumettre_acheteur|
            valider_responsable_achat|rejeter_responsable_achat|rejeter_chef_projet|valider_chef_projet|
            cloturer_chef_projet|avis_projet_controleur_gestion|rejeter_directeur_achat|valider_directeur_achat')
            ->only('update_statuts');
        $this->middleware('permission:delete_projet')->only('destroy');
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\Response
     */
    public function index()
    {
        // Liste des filtres
        $paats = Paat::getAllPaatsByStructureId(Auth::user()->structure_id);
        // On récupère l'id du paat que l'on souhaite afficher -> par defaut on prends le paat courant
        $paat_id = Session::get('paat_id') != null ? Session::get('paat_id')
            : Paat::where('structure_id', Auth::user()->structure_id)->where('statut', PAAT_STATUT::EN_COURS)->first()->id ?? array_key_first($paats) ?? null;

        $directions = Direction::select('id', 'nom')->where('structure_id', Auth::user()->structure_id)->get();
        $direction_id = Session::get('direction_id');
        $service_id = Session::get('service_id');

        $familles = Famille::where('structure_id', Auth::user()->structure_id)->pluck('nom', 'id');
        $famille_id = Session::get('famille_id');

        // On récupère la collection projets -> le paat_id n'est jamais null
        $projets = Projet::join('paats', 'paats.id', '=', 'projets.paat_id')
            ->where('projets.structure_id', Auth::user()->structure_id);

        // On ajoute les conditions de filtres
        $projets = Projet::getByFiltresAndRole($projets, $paat_id, $direction_id, $service_id, $famille_id);

        $tmp = clone $projets;
        $spapser = $tmp->join('projets_actions_resp_soc_env', 'projets_actions_resp_soc_env.projet_id', '=', 'projets.id')
            ->join('actions', 'actions.id', '=', 'projets_actions_resp_soc_env.action_id')
            ->join('thematiques', 'thematiques.id', '=', 'actions.thematique_id')
            ->select('thematiques.nom', 'thematiques.description', DB::raw('count(thematiques.id) as total'))
            ->groupBy('thematiques.nom', 'thematiques.description')->get();
        unset($tmp);

        // Onglet performance achat
        $tmp = clone $projets;
        $top_10_projets = $tmp->orderBy('projets.gains_cible', 'DESC')
            ->select('projets.id', 'projets.objet', 'projets.gains_cible', 'projets.gains_notifie', 'projets.montant_reference')
            ->where('report', false)
            ->limit(10)->get();
        unset($tmp);

        $tmp = clone $projets;
        $graphe_directions = $tmp->join('directions', 'directions.id', '=', 'projets.direction_id')
            ->select(DB::raw('IFNULL(directions.nom, \'sans direction\') AS direction'), DB::raw('count(projets.id) AS total'))
            ->where('report', false)
            ->groupBy('directions.nom')->pluck('total', 'direction')->toArray();
        unset($tmp);

        $tmp = clone $projets;
        $graphe_leviers = $tmp->leftJoin('leviers_projets', 'leviers_projets.projet_id', '=', 'projets.id')
            ->leftJoin('leviers', 'leviers.id', '=', 'leviers_projets.levier_id')
            ->select(DB::raw('IFNULL(leviers.nom, \'sans levier\') AS levier'), DB::raw('count(projets.id) AS total'))
            ->where('report', false)->groupBy('leviers.nom')->pluck('total', 'levier')->toArray();
        unset($tmp);

        // Onglet planning
        $tmp = clone $projets;
        $data_planning = $tmp->select('projets.objet', 'projets.date_debut', 'projets.date_fin', 'projets.date_mise_en_oeuvre')->get();
        unset($tmp);

        $planning = [];
        foreach ($data_planning as $p) {
            array_push($planning, [
                'name' => $p->objet,
                'desc' => 'prévu',
                'values' => array([
                    'from' => $p->date_debut,
                    'to' => $p->date_fin,
                    'customClass' => 'ganttBlue'
                ])
            ], [
                'desc' => 'réalisé',
                'values' => array([
                    'from' => $p->date_debut,
                    'to' => $p->date_mise_en_oeuvre,
                    'customClass' => 'ganttGreen'
                ])
            ]);
        }

        // Onglet gains
        $tmp = clone $projets;
        $res = $tmp->select('projets.id', 'projets.owner_id', 'projets.objet', 'gains_achats_complexes_projets.annee', 'gains_achats_complexes_projets.valeur', 'gains_achats_complexes_projets.type')
                    ->join('gains_achats_complexes_projets', 'gains_achats_complexes_projets.projet_id', '=', 'projets.id')
                    ->whereRaw('(gains_achats_complexes_projets.type = \'cible\' OR gains_achats_complexes_projets.type = \'notifie\')')->get();
        unset($tmp);

        $gains = array();
        $max_annee = $min_annee = $res[0]->annee ?? 0;
        // On itére sur tous les résultats de la requête
        foreach($res as $r) {
            // On vérifie si la date du gains est potentiellement la maxmin_annee
            $min_annee = $r->annee < $min_annee ? $r->annee : $min_annee;

            // On vérifie si la date du gains est potentiellement la max_annee
            $max_annee = $r->annee > $max_annee ? $r->annee : $max_annee;

            // on vérifie que le tableau $gains ne possède pas deja le projet
            if (array_key_exists($r->id, $gains)) {
                // Si le projet est deja dans le tableau de gains on ajoute uniquement le nouveau gain
                $gains[$r->id]['gains'][$r->annee][$r->type] = $r->valeur;
            } else {
                // On ajoute un nouvel element dans le tableau de gain
                $gains[$r->id] = [
                    'id' => $r->id,
                    'owner' => User::find($r->owner_id)->nom_complet() ?? '-',
                    'objet' => $r->objet,
                    'gains' => [$r->annee => [$r->type => $r->valeur]]
                ];
            }
        }

        return view('projets.index.index', [
            'paats' => $paats,
            'paat_id' => $paat_id,
            'paat' => Paat::find($paat_id),
            'directions' => $directions,
            'direction_id' => $direction_id,
            'service_id' => $service_id,
            'familles' => $familles,
            'famille_id' => $famille_id,
            'projets' => $projets->select('projets.*')->paginate(APPLICATION::ITEMS_PER_PAGE),
            'spapser' => $spapser,
            // A partir d'ici on ne travail que sur les projets qui ne sont pas des reports
            'gains_cibles' => $projets->where('report', 0)->sum('gains_cible'),
            'gains_notifies' => $projets->sum('gains_notifie'),
            'montant_depenses_traitees' => $projets->sum('montant_reference'),
            'nombre_projets' => $projets->count(),
            'top_10_projets' => $top_10_projets,
            'graphe_directions' => $graphe_directions,
            'graphe_leviers' => $graphe_leviers,
            'planning' => $planning,
            'gains' => $gains,
            'min_annee' => $min_annee,
            'max_annee' => $max_annee
        ]);
    }

    /**
     * Permet de retourner les filtres selectionner pour mettre a jour l'index
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function filtres(Request $request)
    {
        // On split la value pour le service qui est de la forme direction_service
        $split = explode('_', $request->service_id);
        $service_id = end($split);

        // Si l'utilisateur souhaite filtrer les projets
        if ($request->action === 'Filtrer') {
            Session::put('paat_id', $request->paat_id);
            Session::put('direction_id', $request->direction_id);
            Session::put('service_id', $service_id);
            Session::put('famille_id', $request->famille_id);

            // On retourne sur l'index avec les filtres stoqués dans la session
            return redirect()->route('projets.index');
        } elseif ($request->action === 'Exporter') {
            // On exporte la liste des projets
            return Excel::download(new ProjetsExport(
                $request->paat_id,
                $request->direction_id,
                $service_id,
                $request->famille_id
            ), 'projets.xlsx');
        } else {
            abort(403);
        }
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\Response
     */
    public function create()
    {
        return view('projets.form.form', array_merge(
            $this->getListesOnglets(),
            [
                'route' => 'store',
                'paat_alert' => is_null(Paat::where('structure_id', Auth::user()->structure_id)->whereIn('statut', [PAAT_STATUT::EN_COURS, PAAT_STATUT::INITIALISATION])->first()),
                'editable' => true
            ]
        ));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\StoreRequest  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(Request $request)
    {
        $paat_courant = Paat::select('id')->where('structure_id', Auth::user()->structure_id)->whereIn('statut', [PAAT_STATUT::EN_COURS, PAAT_STATUT::INITIALISATION])->first();
        if (isset($paat_courant)) {
            $request->validate([
                'direction_id' => 'required',
                'objet' => 'required|string|max:255',
                'description' => 'nullable|string',
                'budget' => 'required|string',
                'niveau_mutualisation_id' => 'required',
                'operateur_mutualisation_id' => 'required',
                'impact_budgetaire' => 'nullable|numeric|between:0,100',
                'imputation_budgetaire_id' => 'required',
                'programmation' => 'required|boolean',
                'type_calcul_gains' => 'required|integer|between:1,3',
                'ondam' => 'required|boolean',
                'referentiel' => 'nullable|boolean',
                'libelle_marche_a_renouveler' => 'nullable|string|max:255',
                'numero_marche_a_renouveler' => 'nullable|string|max:255',
                'libelle_nouveau_marche' => 'nullable|string|max:255',
                'numero_nouveau_marche' => 'nullable|string|max:255',
                'date_debut' => 'required|date_format:d/m/Y',
                'date_fin' => 'required|date_format:d/m/Y'
            ]);

            // On récupère le prochain id en base pour créer la référence
            $statement = DB::select("SHOW TABLE STATUS LIKE 'projets'");
            $nextId = $statement[0]->Auto_increment;

            // Gestion directions et services
            $direction = $request->direction_id != null ? Direction::find($request->direction_id) : null;
            $split_service = isset($request->service_id) ? explode('_', $request->service_id) : null;
            $service = $split_service != null ? Service::find(end($split_service)) : null;
            if ($service !== null) {
                if ($service->direction_id != $direction->id) {
                    // Normalement on ne rentre jamais dans ce cas
                    abort(403);
                }
            }

            // Gestion familles, domaines, catégories et segments
            $famille = $request->famille_id != null ? Famille::find($request->famille_id) : null;
            $split_domaine = isset($request->domaine_id) ? explode('_', $request->domaine_id) : null;
            $domaine = $split_domaine != null ? Domaine::find(end($split_domaine)) : null;
            $split_categorie = isset($request->categorie_id) ? explode('_', $request->categorie_id) : null;
            $categorie = $split_categorie != null ? Categorie::find(end($split_categorie)) : null;
            $split_segment = isset($request->segment_id) ? explode('_', $request->segment_id) : null;
            $segment = $split_segment != null ? Segment::find(end($split_segment)) : null;

            if (!$this->checkFamilleHierarchie($famille, $domaine, $categorie, $segment)) {
                // Normalement on ne rentre jamais dans ce cas
                abort(403);
            }

            //TODO à supprimer après le 25 juin 2021
            $montant_reference_bidouille = 0;
            if($direction->nom === 'Centre Hospitalier de Vichy' && $request->objet === 'Fluides à usage médicaux et gaz de laboratoire (coût complet)') {
                $montant_reference_bidouille = 163926;
            }
            if($direction->nom === 'Centre Hospitalier de Moulins Yzeure' && $request->objet === 'Fluides à usage médicaux et gaz de laboratoire (coût complet)') {
                $montant_reference_bidouille = 90728;
            }

            $projet = Projet::create(array_merge(
                $request->except(['_token', '_method', 'date_debut', 'date_fin', 'direction_id', 'service_id', 'famille_id', 'domaine_id', 'categorie_id', 'segment_id']),
                [
                    // On ajoute les champs manquants
                    'reference' => 'F-' . $nextId . '-' . date('m') . "-" . date('Y'),
                    'structure_id' => Auth::user()->structure_id,
                    'paat_id' => $paat_courant->id,
                    'owner_id' => Auth::user()->getAuthIdentifier(),
                    'date_debut' => date_create_from_format('d/m/Y', $request->date_debut),
                    'date_fin' => date_create_from_format('d/m/Y', $request->date_fin),
                    // On surcharge certains champs
                    'impact_budgetaire' => $request->impact_budgetaire ?? 0,
                    'direction_id' => $direction->id,
                    'service_id' => $service != null ? $service->id : null,
                    'famille_id' => $famille != null ? $famille->id : null,
                    'domaine_id' => $domaine != null ? $domaine->id : null,
                    'categorie_id' => $categorie != null ? $categorie->id : null,
                    'segment_id' => $segment != null ? $segment->id : null,
                    'renouvellement_marche' => $request->renouvellement_marche,
                    'montant_reference' => $montant_reference_bidouille
                ],
            ))->id;

            // Etape de création
            $this->ajouter_etape(ETAPE_PROJET::CREATION, $projet);
            // Ajout du statut en cours
            ProjetStatut::firstOrCreate([
                'message' => '',
                'user_id' => Auth::user()->getAuthIdentifier(),
                'statut_id' => PROJET_STATUT::EN_COURS,
                'projet_id' => $projet
            ]);
            return redirect()->route('projets.edit', $projet)->with('success', 'Projet ajouté avec succès.');
        } else {
            return redirect()->back()
                ->withInput($request->input())
                ->withErrors(['Impossible de sauvegarder le projet car votre structure ne possède aucun PAAT en cours.']);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\Response
     */
    public function edit($id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet)) {
                $projet->leviers = $projet->leviers()->pluck("levier_id")->toArray();
                $projet->statuts = $projet->projets_statuts()->get();

                $annee_N = date('Y', strtotime($projet->date_debut));
                $annee_N1 = $annee_N + 1;
                // Dans le cas d'un report, on incrémente l'année N pour afficher correctement les valeurs dans la vue
                // if ($projet->report)
                //     $annee_N += 1;

                if ($projet->type_calcul_gains === TYPE_CALCUL_GAINS::ACHATS_COMPLEXES) {
                    $achats_complexes = [];
                    foreach($projet->achats_complexes() as $annee => $row) {
                        $achats_complexes[$annee] = [];
                        foreach($row as $valeur) {
                            $achats_complexes[$annee][$valeur->type] = $valeur->valeur;
                        }
                    }

                    // Si c'est un achat complexe DGOS, on ne renvoie pas un tableau de données mais les données directement
                    if($projet->structure->type_achat_cout_global == 2) {
                        $detail_achats_complexes = reset($achats_complexes);
                    }
                } elseif ($projet->type_calcul_gains === TYPE_CALCUL_GAINS::ACHATS_RECURRENTS || $projet->type_calcul_gains === TYPE_CALCUL_GAINS::ACHATS_INVESTISSEMENT) {
                    $gains_cibles = GainAchatComplexeProjet::where("projet_id", $projet->id)->where('type', 'cible')->orderBy('annee')->first();
                    if ($gains_cibles != null) {
                        $gains_cibles_N = $gains_cibles->valeur;
                    }
                    $gains_notifies = GainAchatComplexeProjet::where("projet_id", $projet->id)->where('type', 'notifie')->orderBy('annee')->first();
                    if ($gains_notifies != null) {
                        $gains_notifies_N = $gains_notifies->valeur;
                    }
                    $gains_realises = GainAchatComplexeProjet::where("projet_id", $projet->id)->where('type', 'securise')->orderBy('annee')->first();
                    if ($gains_realises != null) {
                        $gains_realises_N = $gains_realises->valeur;
                    }
                }

                return view('projets.form.form', array_merge(
                    $this->getListesOnglets($id),
                    [
                        'projet' => $projet,
                        'route' => 'update',
                        'date_fin_comptabilisation' => date($projet->paat->date_fin),
                        'annee_N' => $annee_N,
                        'annee_N1' => $annee_N1,
                        'achats_complexes' => $achats_complexes ?? [],
                        'detail_achats_complexes' => $detail_achats_complexes ?? [],
                        'gains_cibles_N' => $gains_cibles_N ?? 0,
                        'gains_notifies_N' => $gains_notifies_N ?? 0,
                        'gains_realises_N' => $gains_realises_N ?? 0,
                        'editable' => Paat::find($projet->paat_id)->statut != PAAT_STATUT::CLOTURE
                    ]
                ));
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request, $id)
    {
        $request->validate([
            'direction_id' => 'required',
            'objet' => 'required|string|max:255',
            'description' => 'nullable|string',
            'budget' => 'required|string',
            'niveau_mutualisation_id' => 'required',
            'operateur_mutualisation_id' => 'required',
            'impact_budgetaire' => 'nullable|numeric|between:0,100',
            'imputation_budgetaire_id' => 'required',
            'programmation' => 'required|boolean',
            'type_calcul_gains' => 'required|integer|between:1,3',
            'ondam' => 'required|boolean',
            'referentiel' => 'nullable|boolean',
            'libelle_marche_a_renouveler' => 'nullable|string|max:255',
            'numero_marche_a_renouveler' => 'nullable|string|max:255',
            'libelle_nouveau_marche' => 'nullable|string|max:255',
            'numero_nouveau_marche' => 'nullable|string|max:255',
            'date_debut' => 'required|date_format:d/m/Y',
            'date_fin' => 'required|date_format:d/m/Y'
        ]);

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // Gestion directions et services
                $direction = $request->direction_id != null ? Direction::find($request->direction_id) : null;
                $split_service = isset($request->service_id) ? explode('_', $request->service_id) : null;
                $service = $split_service != null ? Service::find(end($split_service)) : null;
                if ($service !== null) {
                    if ($service->direction_id != $direction->id) {
                        // Normalement on ne rentre jamais dans ce cas
                        abort(403);
                    }
                }

                // Gestion familles, domaines, catégories et segments
                $famille = $request->famille_id != null ? Famille::find($request->famille_id) : null;
                $split_domaine = isset($request->domaine_id) ? explode('_', $request->domaine_id) : null;
                $domaine = $split_domaine != null ? Domaine::find(end($split_domaine)) : null;
                $split_categorie = isset($request->categorie_id) ? explode('_', $request->categorie_id) : null;
                $categorie = $split_categorie != null ? Categorie::find(end($split_categorie)) : null;
                $split_segment = isset($request->segment_id) ? explode('_', $request->segment_id) : null;
                $segment = $split_segment != null ? Segment::find(end($split_segment)) : null;

                if (!$this->checkFamilleHierarchie($famille, $domaine, $categorie, $segment)) {
                    // Normalement on ne rentre jamais dans ce cas
                    abort(403);
                }

                $projet->update(array_merge(
                    $request->except(['_token', '_method', 'date_debut', 'date_fin', 'direction_id', 'service_id', 'famille_id', 'domaine_id', 'categorie_id', 'segment_id']),
                    [
                        'date_debut' => date_create_from_format('d/m/Y', $request->date_debut),
                        'date_fin' => date_create_from_format('d/m/Y', $request->date_fin),
                        'impact_budgetaire' => $request->impact_budgetaire ?? 0,
                        'direction_id' => $direction->id,
                        'service_id' => $service != null ? $service->id : null,
                        'famille_id' => $famille != null ? $famille->id : null,
                        'domaine_id' => $domaine != null ? $domaine->id : null,
                        'categorie_id' => $categorie != null ? $categorie->id : null,
                        'segment_id' => $segment != null ? $segment->id : null,
                        'renouvellement_marche' => $request->renouvellement_marche
                    ]
                ));
                return redirect()->route('projets.edit', $projet->id)->with('success', 'Projet mis à jour avec succès.');
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    public function update_leviers(Request $request, $id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                $leviers = $request->leviers;
                if (isset($leviers)) {
                    $projet->leviers()->sync(array_values($leviers));

                } else {
                    $projet->leviers()->detach();
                }
                $this->ajouter_etape(ETAPE_PROJET::LEVIERS, $projet->id);
                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Leviers mis à jour avec succès.',
                    "active" => "leviers"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    public function update_achats_simples(UpdateProjetAchatSimple $request, $id)
    {
        $validated = $request->validated();

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // TODO : en cas de report, il ne faut pas mettre à jour le montant de référence, le % gain cible, etc
                // Pour l'instant c'est géré côté front, mais il faudrait le faire également côté back

                // Calculs des gains
                // Gains cibles = montant référence * % gains cibles
                $gains_cibles = $validated['montant_reference'] *  $validated['pourcentage_gains_cible'] / 100;
                // Gains notifiés = montant référence - montant notifié
                $gains_notifies = $validated['montant_notifie'] ? ($validated['montant_reference'] - $validated['montant_notifie']) : null;
                // Gains réalisés = montant référence - montant réalisé
                $gains_securises = $validated['montant_realise'] ? ($validated['montant_reference'] - $validated['montant_realise']) : null;

                $envoyer_alerte = $projet->montant_reference != $validated['montant_reference']
                                    || $projet->gains_cible != $gains_cibles
                                    || $projet->gains_notifie != $gains_notifies
                                    || $projet->gains_securise != $gains_securises;

                $projet->update([
                    'montant_reference' => $validated['montant_reference'],
                    'pourcentage_gains_cible' => $validated['pourcentage_gains_cible'],
                    'montant_notifie' => $validated['montant_notifie'],
                    'montant_realise' => $validated['montant_realise'],
                    'commentaire' => $validated['commentaire'],
                    'duree_mois' => 12,
                    'date_mise_en_oeuvre' => $validated['date_notification'] ? date_create_from_format('d/m/Y', $validated['date_notification']) : null,
                    'gains_cible' => $gains_cibles,
                    'gains_notifie' => $gains_notifies,
                    'gains_securise' => $gains_securises
                ]);

                GainAchatComplexeProjet::where("projet_id", $projet->id)->where("type", "cible")->delete();
                // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                $nbJoursN = floor((strtotime($projet->paat->date_fin) - strtotime($projet->date_fin)) / (3600 * 24));
                $gains_cibles_N = ceil($gains_cibles * $nbJoursN / 364);
                $gains_cibles_N1 = ceil($gains_cibles * (364 - $nbJoursN) / 364);

                $gains_achats_complexes = [];
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => date('Y', strtotime($projet->date_debut)),
                    "valeur" => $gains_cibles_N,
                    "projet_id" => $projet->id
                ]);
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                    "valeur" => $gains_cibles_N1,
                    "projet_id" => $projet->id
                ]);
                GainAchatComplexeProjet::insert($gains_achats_complexes);


                // S'il y a une date de notification, on reporte également les gains notifiés et sécurisés
                if ($projet->date_mise_en_oeuvre != null) {
                    GainAchatComplexeProjet::where("projet_id", $projet->id)->where("type", "notifie")->delete();
                    // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                    // TODO : petit décalage car $projet->date_mise_en_oeuvre garde les heures à l'enregistrement alors que pas la date de fin du PAAT
                    $nbJoursAnneeNDateNotification = floor((strtotime($projet->paat->date_fin) -  date_timestamp_get($projet->date_mise_en_oeuvre)) / (3600 * 24));
                    $gains_notifie_N = ceil(($gains_notifies * $nbJoursAnneeNDateNotification) / 364);
                    $gains_notifie_N1 = ceil($gains_notifies * ((364 - $nbJoursAnneeNDateNotification) / 364));

                    $gains_achats_complexes = [];
                    array_push($gains_achats_complexes, [
                        "type" => "notifie",
                        "annee" => date('Y', strtotime($projet->date_debut)),
                        "valeur" => $gains_notifie_N,
                        "projet_id" => $projet->id
                    ]);
                    array_push($gains_achats_complexes, [
                        "type" => "notifie",
                        "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                        "valeur" => $gains_notifie_N1,
                        "projet_id" => $projet->id
                    ]);
                    GainAchatComplexeProjet::insert($gains_achats_complexes);

                    GainAchatComplexeProjet::where("projet_id", $projet->id)->where("type", "securise")->delete();
                    // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                    $gains_realise_N = ceil(($gains_securises * $nbJoursAnneeNDateNotification) / 364);
                    $gains_realise_N1 = ceil($gains_securises * ((364 - $nbJoursAnneeNDateNotification) / 364));

                    $gains_achats_complexes = [];
                    array_push($gains_achats_complexes, [
                        "type" => "securise",
                        "annee" => date('Y', strtotime($projet->date_debut)),
                        "valeur" => $gains_realise_N,
                        "projet_id" => $projet->id
                    ]);
                    array_push($gains_achats_complexes, [
                        "type" => "securise",
                        "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                        "valeur" => $gains_realise_N1,
                        "projet_id" => $projet->id
                    ]);
                    GainAchatComplexeProjet::insert($gains_achats_complexes);
                }


                // On ajoute l'étape achats
                $this->ajouter_etape(ETAPE_PROJET::ACHATS, $projet->id);

                //Envoi des alertes
                if ($envoyer_alerte) {
                    EnvoyerAlerte::dispatch($projet, Auth::user()->structure_id)->onQueue('emails');
                }

                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Achats simples mis à jour avec succès.',
                    "active" => "achats_simples"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }


    public function update_achats_complexes(UpdateProjetAchatComplexe $request, $id)
    {
        $validated = $request->validated();

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // Init du booleen qui permet de vérifier l'envoi des alertes
                $envoyer_alerte = false;

                $projet->duree_mois = $validated['duree_mois'];
                $projet->pourcentage_gains_cible = $validated['pourcentage_gains_cible'];
                $projet->commentaire = $validated['commentaire'];
                $projet->date_mise_en_oeuvre = $validated['date_notification'] ? date_create_from_format('d/m/Y', $validated['date_notification']) : null;

                // Si le montant de référence global n'a pas bougé, on vérifie les montants de référence, les gains sécurisés et notifiés s'ils ont bougé
                $montants_references_old = MontantAchatComplexeProjet::where([
                    ["projet_id", $projet->id],
                    ["type", "reference"]
                ])->get();
                $gains_notifies_old = GainAchatComplexeProjet::where([
                    ["projet_id", $projet->id],
                    ["type", "notifie"]
                ])->get();
                $gains_securises_old = GainAchatComplexeProjet::where([
                    ["projet_id", $projet->id],
                    ["type", "securise"]
                ])->get();

                // On init des variables pour récupérer le total des montants & gains
                $total_montant_reference = 0;
                $total_montant_realise = 0;
                $total_gains_cible = 0;
                $total_gains_securise = 0;
                $total_gains_notifie = 0;

                // On enlève les anciennes valeurs
                AchatComplexeProjet::where("projet_id", $projet->id)->delete();
                MontantAchatComplexeProjet::where("projet_id", $projet->id)->delete();
                GainAchatComplexeProjet::where("projet_id", $projet->id)->delete();

                // On enregistre les valeurs du tableau "Référentiel" et "Réalisé" par année
                $montants_achats_complexes = [];
                $gains_achats_complexes = [];
                foreach($request->annees as $index => $annee) {
                    // Calcul des montants
                    $valeur_reference = $request->montant_reference_annees[$index] ?? 0;
                    $total_montant_reference += $valeur_reference;
                    $valeur_realise = $request->montant_realise_annees[$index] ?? 0;
                    $total_montant_realise = $valeur_realise;

                    array_push($montants_achats_complexes, [
                        "type" => "reference",
                        "annee" => $annee,
                        "valeur" => $valeur_reference,
                        "projet_id" => $projet->id
                    ]);

                    array_push($montants_achats_complexes, [
                        "type" => "realise",
                        "annee" => $annee,
                        "valeur" => $valeur_realise,
                        "projet_id" => $projet->id
                    ]);

                    // Calcul des gains
                    $valeur_gains_cible = $valeur_reference * $validated['pourcentage_gains_cible'] / 100;
                    $total_gains_cible += $valeur_gains_cible;
                    $valeur_gains_securise = $valeur_reference - $valeur_realise;
                    $total_gains_securise += $valeur_gains_securise;

                    array_push($gains_achats_complexes, [
                        "type" => "cible",
                        "annee" => $annee,
                        "valeur" => $valeur_gains_cible,
                        "projet_id" => $projet->id
                    ]);

                    array_push($gains_achats_complexes, [
                        "type" => "securise",
                        "annee" => $annee,
                        "valeur" => $valeur_gains_securise,
                        "projet_id" => $projet->id
                    ]);
                }
                MontantAchatComplexeProjet::insert($montants_achats_complexes);

                // On enregistre les valeurs du tableau "Notifié" par année
                $enum = [
                    'amortissements_investissements' => 'type_amortissements_investisseurs',
                    'maintenances' => 'type_maintenances',
                    'couts_installations' => 'type_couts_installation',
                    'consommables' => 'type_consommables',
                    'couts_formations' => 'type_couts_formation',
                    'resources_internes' => 'type_ressources_internes',
                    'energies' => 'type_energies',
                    'autres' => 'type_autres'
                ];
                $montants_achats_complexes = [];
                foreach($request->annees as $index => $annee) {
                    $valeur_notifie = 0;
                    foreach($enum as $type_enum => $type_html) {
                        $valeur = $request->{$type_html}[$index] ?? 0;
                        $valeur_notifie += $valeur;

                        array_push($montants_achats_complexes, [
                            "type" => $type_enum,
                            "annee" => $annee,
                            "valeur" => $valeur,
                            "projet_id" => $projet->id
                        ]);
                    }
                    $valeur_reference = $request->montant_reference_annees[$index] ?? 0;
                    $valeur_notifie = $valeur_reference - $valeur_notifie;
                    $total_gains_notifie += $valeur_notifie;
                    array_push($gains_achats_complexes, [
                        "type" => "notifie",
                        "annee" => $annee,
                        "valeur" => $valeur_notifie,
                        "projet_id" => $projet->id
                    ]);
                }

                // On update le projet avec les nouveaux montants
                if ($projet->montant_reference != $total_montant_reference) {
                    $projet->montant_reference = $total_montant_reference;
                    $envoyer_alerte = true;
                }
                if ($projet->gains_cible != $total_gains_cible) {
                    $projet->gains_cible = $total_gains_cible;
                    $envoyer_alerte = true;
                }
                if ($projet->gains_securise != $total_gains_securise) {
                    $projet->gains_securise = $total_gains_securise;
                    $envoyer_alerte = true;
                }

                if ($projet->gains_notifie != $total_gains_notifie) {
                    $projet->gains_notifie = $total_gains_notifie;
                    $envoyer_alerte = true;
                }

                $projet->montant_realise = $total_montant_realise;
                $projet->gains_cible = $total_gains_cible;
                $projet->save();

                // On insère les montants notifiés des achats complexes
                AchatComplexeProjet::insert($montants_achats_complexes);

                // On enregistre les gains des achats complexes
                GainAchatComplexeProjet::insert($gains_achats_complexes);

                // On ajoute l'étape achats
                $this->ajouter_etape(ETAPE_PROJET::ACHATS, $projet->id);

                //Envoi des alertes si une modif a été faite
                if ($envoyer_alerte) {
                    EnvoyerAlerte::dispatch($projet, Auth::user()->structure_id)->onQueue('emails');
                }

                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Achats complexes mis à jour avec succès.',
                    "active" => "achats_complexes"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }


    public function update_achats_complexes_dgos(UpdateProjetAchatComplexeDgos $request, $id)
    {
        $validated = $request->validated();

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // Calcul des années pour les calculs
                $carbon_date_debut = Carbon::createFromFormat('!Y-m-d', $projet->date_debut);
                $anneeN = $carbon_date_debut->year;
                $anneeN1 = $carbon_date_debut->addYear()->year;

                // Calculs des gains
                // Gains cibles = montant référence * % gains cibles
                $gains_cibles = $validated['montant_reference'] *  $validated['pourcentage_gains_cible'] / 100;
                // Gains notifiés = montant référence - montant notifié
                //$gains_notifies = $validated['montant_notifie'] ? ($validated['montant_reference'] - $validated['montant_notifie']) : null;
                // Gains réalisés = montant référence - montant réalisé
                //$gains_securises = $validated['montant_realise'] ? ($validated['montant_reference'] - $validated['montant_realise']) : null;

                // Init du booleen qui permet de vérifier l'envoi des alertes
                $envoyer_alerte = false;

                // On enregistre les valeurs dans la table "Projets"
                $projet->update([
                    'montant_reference' => $validated['montant_reference'],
                    'montant_annuel' => $validated['montant_annuel'],
                    'pourcentage_gains_cible' => $validated['pourcentage_gains_cible'],
                    'montant_notifie' => $validated['montant_notifie'],
                    'moyenne_offres_duree_projet' => $validated['moyenne_offres_duree_projet'],
                    /*'montant_realise' => $validated['montant_realise'],*/
                    'commentaire' => $validated['commentaire'],
                    'duree_mois' => $validated['duree_mois'],
                    'date_mise_en_oeuvre' => $validated['date_notification'] ? date_create_from_format('d/m/Y', $validated['date_notification']) : null,
                    'gains_cible' => $gains_cibles,
                    /*'gains_notifie' => $gains_notifies,
                    'gains_securise' => $gains_securises*/
                ]);

                // On supprime les anciennes valeurs stockés du projet
                AchatComplexeProjet::where("projet_id", $projet->id)->delete();
                MontantAchatComplexeProjet::where("projet_id", $projet->id)->delete();
                GainAchatComplexeProjet::where("projet_id", $projet->id)->delete();

                // On enregistre le détail des composantes de coût
                $enum = [
                    'amortissements_investissements',
                    'maintenances',
                    'couts_installations',
                    'consommables',
                    'couts_formations',
                    'resources_internes',
                    'energies',
                    'autres'
                ];
                $achats_complexes = [];
                $valeur_notifie = 0;
                foreach($enum as $type_enum) {
                    $valeur = $request->{$type_enum} ?? 0;
                    $valeur_notifie += $valeur;

                    array_push($achats_complexes, [
                        "type" => $type_enum,
                        "annee" => $anneeN,
                        "valeur" => $valeur,
                        "projet_id" => $projet->id
                    ]);
                }

                // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                $nbJoursN = floor((strtotime($projet->paat->date_fin) - strtotime($projet->date_fin)) / (3600 * 24));
                $gains_cibles_N = ceil($gains_cibles * $nbJoursN / 364);
                $gains_cibles_N1 = ceil($gains_cibles * (364 - $nbJoursN) / 364);
                $gains_achats_complexes = [];
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => $anneeN,
                    "valeur" => $gains_cibles_N ?? 0,
                    "projet_id" => $projet->id
                ]);
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => $anneeN1,
                    "valeur" => $gains_cibles_N1 ?? 0,
                    "projet_id" => $projet->id
                ]);

                /*
                    TODO : factoriser dans un helper tous les calculs relatifs aux gains
                    (calcul du nombre de jours pour une année au prorata, calcul des différents types de gains,
                    formules communes entre les fiches, etc.)
                */
                // On traite les valeurs qui sont découpées sur plusieurs années
                $arrayAnnees = array($anneeN, $anneeN1);
                $montants_achats_complexes = [];
                foreach ($arrayAnnees as $index => $annee) {
                    // Montant réalisé
                    array_push($montants_achats_complexes, [
                        "type" => "realise",
                        "annee" => $annee,
                        "valeur" => $request["montant_realise"][$index] ?? 0,
                        "projet_id" => $projet->id
                    ]);

                    // Gains sécurisés

                    // Gains sécurisés en %


                }



                // On insère les montants notifiés des achats complexes
                GainAchatComplexeProjet::insert($gains_achats_complexes);
                AchatComplexeProjet::insert($achats_complexes);
                MontantAchatComplexeProjet::insert($montants_achats_complexes);


                // On ajoute l'étape achats
                $this->ajouter_etape(ETAPE_PROJET::ACHATS, $projet->id);

                //Envoi des alertes si une modif a été faite
                if ($envoyer_alerte) {
                    EnvoyerAlerte::dispatch($projet, Auth::user()->structure_id)->onQueue('emails');
                }

                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Achats complexes mis à jour avec succès.',
                    "active" => "achats_complexes"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }


    public function update_achats_investissements(UpdateProjetAchatInvestissement $request, $id)
    {
        $validated = $request->validated();

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // Calculs des gains
                $nbAnnees = $validated['duree_mois'] / 12;
                // Gains cibles = (montant estimé / nombre d'années) * % gains cibles
                $gains_cibles = ($validated['montant_reference'] / $nbAnnees) *  $validated['pourcentage_gains_cible'] / 100;
                // Gains notifiés = (moyenne des offres - montant notifié) / nombre d'années
                $gains_notifies = $validated['montant_notifie'] && $validated['moyenne_offres'] ?
                        (($validated['moyenne_offres'] - $validated['montant_notifie']) / $nbAnnees) :
                            null;
                // Gains réalisés = montant référence - montant réalisé
                $gains_securises = $validated['montant_realise'] ? ($validated['montant_reference'] - $validated['montant_realise']) : null;

                $envoyer_alerte = $projet->montant_reference != $validated['montant_reference']
                                    || $projet->gains_cible != $gains_cibles
                                    || $projet->gains_notifie != $gains_notifies
                                    || $projet->gains_securises != $gains_securises;

                $projet->update([
                    'type_achat_investissement' => $validated['type_achat_investissement'],
                    'duree_mois' => $validated['duree_mois'],
                    'date_mise_en_oeuvre' => $validated['date_notification'] ? date_create_from_format('d/m/Y', $validated['date_notification']) : null,
                    'montant_reference' => $validated['montant_reference'],
                    'pourcentage_gains_cible' => $validated['pourcentage_gains_cible'],
                    'montant_notifie' => $validated['montant_notifie'],
                    'moyenne_offres' => $validated['moyenne_offres'],
                    'montant_realise' => $validated['montant_realise'],
                    'commentaire' => $validated['commentaire'],
                    'gains_cible' => $gains_cibles,
                    'gains_notifie' => $gains_notifies,
                    'gains_securise' => $gains_securises
                ]);


                GainAchatComplexeProjet::where("projet_id", $projet->id)->delete();
                // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                $nbJoursN = floor((strtotime($projet->paat->date_fin) - strtotime($projet->date_fin)) / (3600 * 24));
                $gains_cibles_N = ceil($gains_cibles * $nbJoursN / 364);
                $gains_cibles_N1 = ceil($gains_cibles * (364 - $nbJoursN) / 364);

                $gains_achats_complexes = [];
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => date('Y', strtotime($projet->date_debut)),
                    "valeur" => $gains_cibles_N,
                    "projet_id" => $projet->id
                ]);
                array_push($gains_achats_complexes, [
                    "type" => "cible",
                    "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                    "valeur" => $gains_cibles_N1,
                    "projet_id" => $projet->id
                ]);
                GainAchatComplexeProjet::insert($gains_achats_complexes);

                // S'il y a une date de notification, on reporte également les gains notifiés et sécurisés
                if ($projet->date_mise_en_oeuvre != null) {
                    GainAchatComplexeProjet::where("projet_id", $projet->id)->where("type", "notifie")->delete();
                    // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                    // TODO : petit décalage car $projet->date_mise_en_oeuvre garde les heures à l'enregistrement alors que pas la date de fin du PAAT
                    $nbJoursAnneeNDateNotification = floor((strtotime($projet->paat->date_fin) -  date_timestamp_get($projet->date_mise_en_oeuvre)) / (3600 * 24));
                    $gains_notifie_N = ceil(($gains_notifies * $nbJoursAnneeNDateNotification) / 364);
                    $gains_notifie_N1 = ceil($gains_notifies * ((364 - $nbJoursAnneeNDateNotification) / 364));

                    $gains_achats_complexes = [];
                    array_push($gains_achats_complexes, [
                        "type" => "notifie",
                        "annee" => date('Y', strtotime($projet->date_debut)),
                        "valeur" => $gains_notifie_N,
                        "projet_id" => $projet->id
                    ]);
                    array_push($gains_achats_complexes, [
                        "type" => "notifie",
                        "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                        "valeur" => $gains_notifie_N1,
                        "projet_id" => $projet->id
                    ]);
                    GainAchatComplexeProjet::insert($gains_achats_complexes);

                    GainAchatComplexeProjet::where("projet_id", $projet->id)->where("type", "securise")->delete();
                    // On enregistre la ventilation des gains cibles, au cas où la fiche projet est sujette à un report de PAAT
                    $gains_realise_N = ceil(($gains_securises * $nbJoursAnneeNDateNotification) / 364);
                    $gains_realise_N1 = ceil($gains_securises * ((364 - $nbJoursAnneeNDateNotification) / 364));

                    $gains_achats_complexes = [];
                    array_push($gains_achats_complexes, [
                        "type" => "securise",
                        "annee" => date('Y', strtotime($projet->date_debut)),
                        "valeur" => $gains_realise_N,
                        "projet_id" => $projet->id
                    ]);
                    array_push($gains_achats_complexes, [
                        "type" => "securise",
                        "annee" => (date('Y', strtotime($projet->date_debut)) + 1),
                        "valeur" => $gains_realise_N1,
                        "projet_id" => $projet->id
                    ]);
                    GainAchatComplexeProjet::insert($gains_achats_complexes);
                }


                // On ajoute l'étape achats
                $this->ajouter_etape(ETAPE_PROJET::ACHATS, $projet->id);

                //Envoi des alertes
                if ($envoyer_alerte) {
                    EnvoyerAlerte::dispatch($projet, Auth::user()->structure_id)->onQueue('emails');
                }

                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Achats ponctuels mis à jour avec succès.',
                    "active" => "achats_investissements"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }


    public function update_statuts(Request $request, $id)
    {
        $request->validate([
            'statut_id' => 'required|int'
        ]);

        $statut_id = $request->statut_id;
        $statut = Statut::find($statut_id);

        $projet = Projet::find($id);

        if (isset($projet) && isset($statut)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                // On ajoute le statut au projet
                ProjetStatut::firstOrCreate([
                    'message' => $request->message ?? "",
                    'user_id' => Auth::user()->getAuthIdentifier(),
                    'statut_id' => $statut->id,
                    'projet_id' => $projet->id,
                ]);

                // On met à jour le statut
                if ($statut->id === PROJET_STATUT::SOUMISE) {
                    $projet->update([
                        'soumis' => 1
                    ]);
                } elseif ($statut->id == PROJET_STATUT::CLOTUREE) {
                    $projet->update([
                        'cloture' => 1,
                    ]);
                }

                // On ajoute l'etape statut
                $this->ajouter_etape(ETAPE_PROJET::STATUT, $projet->id);

                // On envoie une notification à celui qui a créé le projet
                $this->envoyer_notification($projet, $statut);

                return redirect()->route('projets.edit', $projet->id)->with([
                    "success" => 'Statut mis à jour avec succès.',
                    "active" => "statuts"
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy($id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet)) {
                if ($projet->statuts->where('statut_id', '!=', PROJET_STATUT::EN_COURS)->count() > 0) {
                    return redirect()->back()->withErrors('Impossible de supprimer le projet car il a déjà été étudié par d\'autres utilisateurs.');
                }

                $projet->delete();
                return redirect()->route('projets.index')->with('success', 'Projet supprimé avec succès.');
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Permet d'ajouter un membre au projet
     * @param Request $request
     * @param int $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function ajouter_membre(Request $request, int $id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet)) {
                // On vérifie que l'utilisateur ajouté soit bien de la même direction ou soit un expert
                $user = User::find($request->membre);
                if (isset($user)) {
                    if ($user->structure_id == Auth::user()->structure_id) {
                        $membre = MembreProjet::where('projet_id', $id)->where('user_id', $user->id)->first();

                        if (isset($membre)) {
                            return redirect()->route('projets.edit', $projet->id)->with([
                                'success' => 'L\'utilisateur est déjà présent dans l\'équipe projet.',
                                'active' => 'gestion_projet'
                            ]);
                        } else {
                            MembreProjet::create([
                                'projet_id' => $id,
                                'user_id' => $user->id
                            ]);
                            $this->ajouter_etape(ETAPE_PROJET::GESTION_PROJET, $projet->id);
                            return redirect()->route('projets.edit', $projet->id)->with([
                                'success' => 'L\'utilisateur a bien été ajouté au projet.',
                                'active' => 'gestion_projet'
                            ]);
                        }
                    } else {
                        abort(403);
                    }
                } else {
                    abort(404);
                }
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Permet de supprimer un membre d'un projet
     * @param Request $request
     * @param int $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function supprimer_membre(Request $request, int $id, int $user_id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet)) {
                $user = User::find($user_id);
                if (isset($user)) {
                    MembreProjet::where('projet_id', $id)->where('user_id', $user->id)->delete();
                    return redirect()->route('projets.edit', $projet->id)->with([
                        'success' => 'L\'utilisateur a bien été supprimé du projet.',
                        'active' => 'gestion_projet'
                    ]);
                } else {
                    abort(404);
                }
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Permet de mettre à jour les actions resp soc env d'un projet
     * @param Request $request
     * @param int $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update_resp_soc_env(Request $request, int $id)
    {
        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                $actions_ids = array_values($request->input('action_rse', []));
                $actions = Action::whereIn('id', $actions_ids)->get();
                if (isset($actions)) {
                    //On supprime les actions resp soc env liées au projet qui ne sont pas envoyées dans la requête
                    ProjetActionRespSocEnv::where('projet_id', $projet->id)
                        ->whereNotIn('action_id', $actions_ids)->delete();
                    foreach ($actions as $a) {
                        ProjetActionRespSocEnv::updateOrCreate(
                            [
                                'projet_id' => $projet->id,
                                'action_id' => $a->id,
                            ],
                            [
                                'action_unite_oeuvre_id' => $request->input('unite_oeuvre_rse')[$a->id],
                                'cible' => $request->input('cible-rse')[$a->id],
                                'notifie' => $request->input('notifie-rse')[$a->id],
                                'realise' => $request->input('realise-rse')[$a->id],
                            ]
                        );
                    }
                    $this->ajouter_etape(ETAPE_PROJET::RESP_SOC_ENV, $projet->id);
                    return redirect()->route('projets.edit', $projet->id)->with([
                        'success' => 'Actions mises à jour avec succès.',
                        'active' => 'resp.soc.env'
                    ]);
                } else {
                    abort(404);
                }
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    public function update_suivi(UpdateProjetSuivi $request, int $id)
    {
        $validated = $request->validated($request);

        $projet = Projet::find($id);
        if (isset($projet)) {
            if (Projet::checkIfUserCanEditOrDestroy($projet, true)) {
                $array_edit_niveau_priorite = [];
                if (Auth::user()->can("edit_niveau_priorite")) {
                    $array_edit_niveau_priorite['niveau_priorite'] = $validated['niveau_priorite'];
                }
                $projet->update(array_merge(
                    $array_edit_niveau_priorite,
                    [
                        'prochaine_echeance' => date_create_from_format('d/m/Y', $validated['prochaine_echeance']),
                        'prochaine_etape' => $validated['prochaine_etape'],
                        'etat_avancement' => $validated['etat_avancement'],
                        'risque' => $validated['risque'],
                    ]
                ));
                $this->ajouter_etape(ETAPE_PROJET::SUIVI, $projet->id);
                return redirect()->route('projets.edit', $projet->id)->with([
                    'success' => 'Le suivi du projet a été mis à jour avec succès.',
                    'active' => 'suivi'
                ]);
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    public function recherche(Request $request)
    {
        $projets = Projet::select('projets.id', 'projets.paat_id', 'projets.structure_id', 'projets.reference', 'projets.owner_id', 'projets.objet', 'projets.description', 'projets.created_at', 'projets.updated_at')
                    ->join('users', 'users.id', '=', 'projets.owner_id')
                    ->where('projets.structure_id', Auth::user()->structure_id)
                    ->where(function ($query) use ($request) {
                        $query->where('projets.objet', 'LIKE', '%' . $request->recherche . '%')
                        ->orWhere('projets.description', 'LIKE', '%' . $request->recherche . '%')
                        ->orWhere('projets.reference', 'LIKE', '%' . $request->recherche . '%')
                        ->orWhere('users.nom', 'LIKE', '%' . $request->recherche . '%')
                        ->orWhere('users.prenom', 'LIKE', '%' . $request->recherche . '%');
                    })->get();

        return view('projets.recherche.index', [
            'recherche' => $request->recherche,
            'projets' => $projets
        ]);
    }

    /**
     * Méthode qui permet de dupliquer une fiche projet
     * Référence : https://stackoverflow.com/a/34032304
     * Référence "Many to many": https://stackoverflow.com/a/42470127
     */
    public function dupliquer(int $id)
    {
        $projet = Projet::find($id);
        $projet->load($projet->getRelationshipsToDuplicate());
        if (isset($projet)) {
            $paat_courant = Paat::select('id')->where('structure_id', Auth::user()->structure_id)->whereIn('statut', [PAAT_STATUT::EN_COURS, PAAT_STATUT::INITIALISATION])->first();
            if (Projet::checkIfUserCanEditOrDestroy($projet) && isset($paat_courant)) {
                // On duplique le projet pour créer un nouvel id
                $projectDuplicated = $projet->replicate();
                $projectDuplicated->paat_id = $paat_courant->id;
                $projectDuplicated->push();

                // Many to many : on duplique les lignes dans les tables associatives
                foreach($projet->getRelations() as $relation => $items) {
                    foreach($items as $item) {
                        if (isset($item->pivot)) {
                            $extra_attributes = Arr::except($item->pivot->getAttributes(), $item->pivot->getForeignKey());
                            $projectDuplicated->{$relation}()->attach($item, $extra_attributes);
                        } else {
                            unset($item->id);
                            $projectDuplicated->{$relation}()->create($item->toArray());
                        }
                    }
                }

                return redirect()->route('projets.edit', $projectDuplicated->id)->with('success', 'Projet dupliqué avec succès.');
            } else {
                abort(403);
            }
        } else {
            abort(404);
        }
    }

    /**
     * Récupère les éléments des différentes listes dans l'écran de création/modification d'un projet
     * @param projet_id id du projet qui permet de récupérer des listes spécifiques
     */
    private function getListesOnglets($projet_id = null)
    {
        // Onglet Création
        $nom_structure = Structure::where('id', Auth::user()->structure_id)->first()->nom;
        $champ_referentiel = Structure::where('id', Auth::user()->structure_id)->first()->champ_referentiel;
        $etablissements = Direction::where('structure_id', Auth::user()->structure_id)->pluck("nom", "id");
        $services_utilisateurs = Service::select('services.id', 'services.nom', 'services.direction_id')
                    ->join('directions', 'directions.id', '=', 'services.direction_id')
                    ->where('directions.structure_id', Auth::user()->structure_id)->get();
        $mutualisations = NiveauMutualisation::where('structure_id', Auth::user()->structure_id)->pluck("nom", "id");
        $centrales_achats = OperateurMutualisation::where('structure_id', Auth::user()->structure_id)->pluck("nom", "id");
        $imputations_budegetaires = ImputationBudgetaire::where('structure_id', Auth::user()->structure_id)->pluck("nom", "id");
        $familles = Famille::select('id', 'nom')->where('structure_id', Auth::user()->structure_id)->get();
        $domaines = Domaine::select('domaines.id', 'domaines.nom', 'domaines.famille_id')
                    ->join('familles', 'familles.id', 'domaines.famille_id')
                    ->where('familles.structure_id', Auth::user()->structure_id)->get();
        $categories = Categorie::select('categories.id', 'categories.nom', 'categories.domaine_id')
                    ->join('domaines', 'domaines.id', 'categories.domaine_id')
                    ->join('familles', 'familles.id', 'domaines.famille_id')
                    ->where('familles.structure_id', Auth::user()->structure_id)->get();
        $segments = Segment::select('segments.id', 'segments.nom', 'segments.categorie_id')
                    ->join('categories', 'categories.id', 'segments.categorie_id')
                    ->join('domaines', 'domaines.id', 'categories.domaine_id')
                    ->join('familles', 'familles.id', 'domaines.famille_id')
                    ->where('familles.structure_id', Auth::user()->structure_id)->get();


        $liste = [
            "nom_structure" => $nom_structure,
            'champ_referentiel' => $champ_referentiel,
            "etablissements" => $etablissements,
            "services_utilisateurs" => $services_utilisateurs,
            "mutualisations" => $mutualisations,
            "centrales_achats" => $centrales_achats,
            "imputations_budegetaires" => $imputations_budegetaires,
            "familles" => $familles,
            "domaines" => $domaines,
            'categories' => $categories,
            'segments' => $segments
        ];

        if (isset($projet_id)) {
            // Onglet Leviers
            $leviers = Levier::where('structure_id', Auth::user()->structure_id)->pluck("nom", "id");
            $liste["leviers"] = $leviers;

            // Onglet gestion projet
            $liste['users'] = User::where('structure_id', Auth::user()->structure_id)->where('active', true)->get();

            // Onglet Resp.Soc.Env
            $liste['thematiques'] = Thematique::where('structure_id', Auth::user()->structure_id)->get();
            $liste['actions_unite_oeuvre'] = ActionUniteOeuvre::orderBy('libelle')->get();
            $liste['actions_checked'] = ProjetActionRespSocEnv::select('action_id', 'action_unite_oeuvre_id', 'cible', 'notifie', 'realise')
                ->where('projet_id', $projet_id)
                ->get()
                ->keyBy('action_id')
                ->toArray()
            ;

            //Onglet Gestion projet
            if (Session::get('tache') != null) {
                $liste['tache'] = Session::get('tache');
            }
            // Onglet fichier
            if (Session::get('fichier') != null) {
                $liste['fichier'] = Session::get('fichier');
            }
        }

        return $liste;
    }

    /**
     * Permet de mettre à jour les étapes du projet
     * @param string $etape
     * @param int $projet_id
     */
    private function ajouter_etape(string $etape, int $projet_id)
    {
        EtapeProjet::firstOrCreate([
            'etape' => $etape,
            'projet_id' => $projet_id
        ]);
    }

    /**
     * Permet de check l'intégrité des données pour les familles, domaines, categories et segments associés au projet
     * @param $famille
     * @param $domaine
     * @param $categorie
     * @param $segment
     * @return bool
     */
    private function checkFamilleHierarchie($famille, $domaine, $categorie, $segment)
    {
        if ($famille != null && $famille->structure_id != Auth::user()->structure_id) {
            return false;
        } else {
            if (($domaine != null && $famille == null) || ($domaine != null && $domaine->famille_id != $famille->id)) {
                return false;
            } else {
                if (($categorie != null && ($domaine == null || $famille == null)) || ($categorie != null && $categorie->domaine_id != $domaine->id)) {
                    return false;
                } else {
                    if (($segment != null && ($categorie == null || $domaine == null || $famille == null)) || ($segment != null && $segment->categorie_id != $categorie->id)) {
                        return false;
                    } else {
                        return true;
                    }
                }
            }
        }
    }


    /**
     * Envoie une notification concernant un nouveau statut sur un projet
     * Si c'est l'initiateur du projet qui a fait la modification, on prévient sa hiérarchie
     * Sinon on prévient l'initiateur que quelqu'un a modifié son projet
     */
    private function envoyer_notification($projet, $statut)
    {
        $owner = User::find($projet->owner_id);
        if (isset($owner)) {
            $message = Auth::user()->prenom . " " . Auth::user()->nom;  // Prénom Nom
            $message .= " (" . Auth::user()->nom_role() . ") ";          // (rôle)

            switch ($statut->id) {
                case PROJET_STATUT::SOUMISE:
                    $message .= 'a soumis le projet "' . $projet->objet . '" pour validation';
                    break;
                case PROJET_STATUT::VALIDEE_RESPONSABLE_ACHAT:
                    $message .= 'a validé le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::REJETEE_RESPONSABLE_ACHAT:
                    $message .= 'a rejeté le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::VALIDEE_CHEF_PROJET:
                    $message .= 'a validé le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::REJETEE_CHEF_PROJET:
                    $message .= 'a rejeté le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::VALIDEE_DIRECTEUR_ACHAT:
                    $message .= 'a validé le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::AVIS_FAVORABLE_CONTROLEUR:
                case PROJET_STATUT::AVIS_DEFAVORABLE_CONTROLEUR:
                    $message .= 'a émis un avis ' . ($statut->id == PROJET_STATUT::AVIS_FAVORABLE_CONTROLEUR ? 'favorable' : 'défavorable');
                    $message .= ' sur le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::CLOTUREE:
                    $message .= 'a clôturé le projet "' . $projet->objet . '"';
                    break;
                case PROJET_STATUT::ABANDONNEE:
                case PROJET_STATUT::SUSPENDUE:
                case PROJET_STATUT::SUPPRIMEE:
                    // On supprime la fiche projet donc pas de notification
                    return;
                default:
                    $message .= 'a mis à jour le projet "' . $projet->objet . '" avec un statut inconnu';
                    break;
            }

            // Soit on prévient le responsable achat, ou le directeur achat s'il n'y en a pas
            if ($owner->id === Auth::user()->getAuthIdentifier()) {
                $envoi_directeurs_achats = false;
                $profil_portefeuille_acheteur = PortefeuilleAcheteur::where("id", Auth::user()->portefeuille_acheteur_id)->exists();
                // Si c'est un acheteur qui modifie son projet, on prévient sa hiérarchie
                if ($profil_portefeuille_acheteur) {
                    $responsables_achat = User::join("portefeuilles_responsables_achats", "portefeuilles_responsables_achats.id", "=", "users.portefeuille_responsable_achat_id")
                        ->join("portefeuilles_acheteurs", "portefeuilles_acheteurs.portefeuille_responsable_achat_id", "=", "portefeuilles_responsables_achats.id")
                        ->where("portefeuilles_acheteurs.id", Auth::user()->portefeuille_acheteur_id)->where('users.active', true)
                        ->select("users.*")
                        ->get();
                    if (isset($responsables_achat) && $responsables_achat->count() > 0) {
                        foreach($responsables_achat as $responsable) {
                            $responsable->notify(new AlerteNotification($message, $projet->id));
                        }
                    } else {
                        $envoi_directeurs_achats = true;
                    }
                } else {
                    $envoi_directeurs_achats = true;
                }
                // S'il n'y a pas de responsable achat, on envoie aux directeurs achat
                if ($envoi_directeurs_achats) {
                    $directeurs_achat = User::role(ROLE::DIRECTEUR_ACHAT . '_' . Auth::user()->structure_id)->where('users.active', true)->get();
                    foreach($directeurs_achat as $directeur) {
                        $directeur->notify(new AlerteNotification($message, $projet->id));
                    }
                }
            }
            // Soit on prévient l'initiateur du projet
            else {
                $owner->notify(new AlerteNotification($message, $projet->id));
            }
        }
    }
}
