<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Laravelista\Comments\Commentable;
use Laravelista\Comments\Comment;
use PAAT_STATUT;
use ROLE;

class Projet extends Model
{
    use HasFactory;
    use Commentable;

    public static function boot()
    {
        parent::boot();

        static::deleting(function ($projet) {
            $projet->membres_projets()->delete();
            $projet->etapes_projets()->delete();
            $projet->leviers_projets()->delete();
            $projet->montants_projets()->delete();
            $projet->achats_complexes_projets()->delete();
            $projet->gains_projets()->delete();
            $projet->actions_resp_soc_env()->delete();
            $projet->taches()->delete();

            // On delete tous les fichiers associés au projet
            foreach ($projet->fichiers as $f) {
                // On delete le lien entre le fichier et le projet
                FichierHasProjet::where('projet_id', $projet->id)->where('fichier_id', $f->id)->delete();
                // On delete le fichier dans le storage
                Storage::delete($f->url);
                // On supprime le fichier en DB
                $f->delete();
            }

            // Ici on ne supprime que le statuts 'en cours' -> voir dans le controller projet
            // Il n'est pas possible de supprimer un projet si un autre statut est posté
            $projet->statuts()->delete();
        });
    }

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'reference',
        'finess',
        'description',
        'objet',
        'date_debut',
        'date_fin',
        'date_mise_en_oeuvre',
        'code_nomenclature',
        'budget',
        'libelle_marche_a_renouveler',
        'numero_marche_a_renouveler',
        'renouvellement_marche',
        'libelle_nouveau_marche',
        'numero_nouveau_marche',
        'programmation',
        'ondam',
        'referentiel',
        'niveau_priorite',
        'montant_reference',
        'montant_notifie',
        'montant_realise',
        'montant_annuel',
        'moyenne_offres_duree_projet',
        'type_calcul_gains',
        'impact_budgetaire',
        'pourcentage_gains_cible',
        'gains_cible',
        'gains_securise',
        'gains_notifie',
        'type_achat_investissement',
        'moyenne_offres',
        'duree_mois',
        'commentaire',
        'programme',
        'soumis',
        'prochaine_echeance',
        'prochaine_etape',
        'etat_avancement',
        'cloture',
        'valide_controleur_gestion',
        'risque',
        'statut_procedure',
        'paat_id',
        'owner_id',
        'structure_id',
        'direction_id',
        'service_id',
        'niveau_mutualisation_id',
        'operateur_mutualisation_id',
        'imputation_budgetaire_id',
        'famille_id',
        'domaine_id',
        'categorie_id',
        'segment_id',
    ];

    /**
     * Liste des clés étrangères à inclure lorsqu'on duplique un projet
     */
    protected $relationshipsToDuplicate = [
        // 'actions',
        'membres_projets',
        'etapes_projets',
        'leviers_projets',
        'statuts',
        'fichiers',
        'actions_resp_soc_env',
        'taches',
        'montants_projets',
        'achats_complexes_projets',
        'gains_projets'
    ];

    public function getRelationshipsToDuplicate()
    {
        return $this->relationshipsToDuplicate;
    }



    /**
     * Permet de filtrer les projet qu'un utilisateurs peut voir en fonction de son role
     * Utilisé dans ProjetController::index et ProjetsExport::collection
     * @param $collection
     * @param $paat_id
     * @param $direction_id
     * @param $service_id
     * @param $famille_id
     * @return mixed
     */
    public static function getByFiltresAndRole($collection, $paat_id, $direction_id, $service_id, $famille_id)
    {
        if ($paat_id != null) {
            $collection->where('projets.paat_id', $paat_id);
        }
        if ($direction_id != null) {
            $collection->where('projets.direction_id', $direction_id);
        }
        if ($service_id != null) {
            $collection->where('projets.service_id', $service_id);
        }
        if ($famille_id != null) {
            $collection->where('projets.famille_id', $famille_id);
        }

        switch (Auth::user()->nom_role()) {
            case ROLE::DIRECTEUR:
                // Si l'utilisateur est un directeur, on affiche uniquement les projets de son etablissement et ceux dont il fait partie
                $tmp = clone $collection;
                $projets_membre_id = $tmp->leftJoin('membres_projets', 'membres_projets.projet_id', '=', 'projets.id')
                    ->where('membres_projets.user_id', Auth::user()->getAuthIdentifier())->pluck('projets.id')->toArray();
                unset($tmp);

                // On récupère les projets qui font partie de sa direction
                $collection->Where('projets.direction_id', Auth::user()->direction_id)
                    ->orWhere('projets.owner_id', Auth::user()->getAuthIdentifier())
                    ->orWhereIn('projets.id', array_values($projets_membre_id));
                break;
            case ROLE::RESPONSABLE_ACHAT:
                // Si l'utilisateur est un responsable achat, on affiche les projets de ses acheteurs ou ceux dont il fait partie.
                $tmp = clone $collection;
                $projets_membre_id = $tmp->leftJoin('membres_projets', 'membres_projets.projet_id', '=', 'projets.id')
                    ->leftJoin('users', 'users.id', '=', 'projets.owner_id')
                    ->leftJoin('portefeuilles_acheteurs', 'portefeuilles_acheteurs.id', '=', 'users.portefeuille_acheteur_id')
                    ->leftJoin('portefeuilles_responsables_achats', 'portefeuilles_responsables_achats.id', '=', 'portefeuilles_acheteurs.portefeuille_responsable_achat_id')
                    ->where(function ($query) {
                        $query->where('portefeuilles_responsables_achats.id', Auth::user()->portefeuille_responsable_achat_id)
                        ->orWhere('membres_projets.user_id', Auth::user()->getAuthIdentifier());
                    })->pluck('projets.id')->toArray();
                unset($tmp);

                // On récupère les projets
                $collection->where('projets.owner_id', Auth::user()->getAuthIdentifier())
                    ->orWhereIn('projets.id', array_values($projets_membre_id));
                break;
            case ROLE::ACHETEUR:
                // Si l'utilisateur est un acheteur, on affiche uniquement ces projets ou les projet dans lequel il est membre
                // On récupère les ids des projet dont fait partie l'acheteur en tant que membre projet
                $tmp = clone $collection;
                $projets_membre_id = $tmp->leftJoin('membres_projets', 'membres_projets.projet_id', '=', 'projets.id')
                    ->where('membres_projets.user_id', Auth::user()->getAuthIdentifier())->pluck('projets.id')->toArray();
                unset($tmp);

                // On récupère les projets de l'acheteur ou ceux dont il fait partie
                $collection->Where('projets.owner_id', Auth::user()->getAuthIdentifier())
                    ->orWhereIn('projets.id', array_values($projets_membre_id));
                break;
            case ROLE::EQUIPE_PROJET:
                // Si l'utilisateur a pour role equipe projet, on affiche les projets dont il fait partie
                $collection->join('membres_projets', 'membres_projets.projet_id', '=', 'projets.id')
                    ->where('membres_projets.user_id', Auth::user()->getAuthIdentifier());
                break;
        }
        return $collection;
    }

    /**
     * Permet de filtrer les projet que le responsable performance ARS peut exporter
     * Utilisé dans RespArsPaatsExport::collection
     * @param $paat_id
     * @param $structure_id
     * @return mixed
     */
    public static function getByPaatAndStructure($paat_id = -1, $structure_id = -1)
    {
        $projets = Projet::query();

        // Si dans l'écran on a filtré par année et/ou structure, on applique les filtres
        if ($paat_id != -1) {
            $projets->where('projets.paat_id', $paat_id);
        }
        if ($structure_id != -1) {
            $projets->where('projets.structure_id', $structure_id);
        }

        $projets->join('structures', 'projets.structure_id', 'structures.id')->where('structures.consolidation_id', '=', Auth::user()->structure->consolidation_id);
        $projets->select('projets.*');

        return $projets->get();
    }

    /**
     * Retourne le PAAT d'un projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function paat()
    {
        return $this->belongsTo(Paat::class);
    }

    public function structure()
    {
        return $this->belongsTo(Structure::class);
    }

    public function direction()
    {
        return $this->belongsTo(Direction::class);
    }

    public function service()
    {
        return $this->belongsTo(Service::class);
    }

    public function famille()
    {
        return $this->belongsTo(Famille::class);
    }

    public function domaine()
    {
        return $this->belongsTo(Domaine::class);
    }

    public function categorie()
    {
        return $this->belongsTo(Categorie::class);
    }

    public function segment()
    {
        return $this->belongsTo(Segment::class);
    }

    public function niveau_mutualisation()
    {
        return $this->belongsTo(NiveauMutualisation::class);
    }

    public function operateur_mutualisation()
    {
        return $this->belongsTo(OperateurMutualisation::class);
    }

    public function imputation_budgetaire()
    {
        return $this->belongsTo(ImputationBudgetaire::class);
    }

    public function actions()
    {
        return $this->belongsToMany(Action::class, 'projets_actions_resp_soc_env', 'projet_id', 'action_id');
    }

    public function membres()
    {
        return $this->belongsToMany(User::class, 'membres_projets', 'projet_id', 'user_id');
    }

    public function achats_complexes()
    {
        $achats_complexes_projets = $this->hasMany(AchatComplexeProjet::class)->get();
        $montants_complexes_projets = $this->hasMany(MontantAchatComplexeProjet::class)->get();
        return($achats_complexes_projets->concat($montants_complexes_projets)->groupBy('annee'));
    }

    /**
     * Retourne l'acheteur qui a initié le projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function acheteur()
    {
        return $this->belongsTo(User::class, 'owner_id');
    }

    /**
     * Permet de retourner toutes les relation MembreProjet du projet
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function membres_projets()
    {
        return $this->hasMany(MembreProjet::class);
    }

    /**
     * Permet de retourner les étapes du projet
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function etapes_projets()
    {
        return $this->hasMany(EtapeProjet::class);
    }

    /**
     * Permet de retourner les étapes du projet -> recupère uniquement le nom de l'étape
     * @return array
     */
    public function etapes()
    {
        return $this->hasMany(EtapeProjet::class)->pluck('etapes_projets.etape')->toArray();
    }

    /**
     * Permet de retourner les relations LevierProjet du projet
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function leviers_projets()
    {
        return $this->hasMany(LevierProjet::class);
    }

    /**
     * Permet de retourner tous les leviers du projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function leviers()
    {
        return $this->belongsToMany(Levier::class, "leviers_projets");
    }

    /**
     * Permet de retourner le dernier statut ajouté au projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function statut()
    {
        return $this->belongsToMany(Statut::class, "projets_statuts")
            ->using(ProjetStatut::class)
            ->orderBy("projets_statuts.created_at", "desc")
            ->take(1);
    }

    /**
     * Retourne les statuts du projet
     * Est uniquement utilisé pour le delete
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function statuts()
    {
        return $this->hasMany(ProjetStatut::class);
    }

    /**
     * Permet de retourner tous les statuts du projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function projets_statuts()
    {
        return $this->belongsToMany(Statut::class, "projets_statuts")
            ->withPivot('user_id')
            ->join('users', 'projets_statuts.user_id', '=', 'users.id')
            ->join('model_has_roles', 'users.id', 'model_has_roles.model_id')
            ->join('roles', 'roles.id', 'model_has_roles.role_id')
            ->select("projets_statuts.*", "statuts.nom", "statuts.icon", "users.nom as user_nom", "users.prenom as user_prenom", "roles.name as fonction");
    }

    /**
     * Retourne les montant du projet si c'est un projet d'achat complexe
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function montants_projets()
    {
        return $this->hasMany(MontantAchatComplexeProjet::class);
    }

    /**
     * Retourne les achats complexes du projet si c'est un projet d'achat complexe
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function achats_complexes_projets()
    {
        return $this->hasMany(AchatComplexeProjet::class);
    }

    /**
     * Retourne les gains du projet si c'est un projet d'achat complexe
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function gains_projets()
    {
        return $this->hasMany(GainAchatComplexeProjet::class);
    }

    /**
     * Retourne les fichiers d'un projet
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function fichiers()
    {
        return $this->belongsToMany(Fichier::class, 'fichiers_has_projets', 'projet_id', 'fichier_id');
    }

    /**
     * Retourne toutes les liaisons entre le projet et les actions
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function actions_resp_soc_env()
    {
        return $this->hasMany(ProjetActionRespSocEnv::class);
    }

    /**
     * Retourne les tâches de gestion de projet
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function taches()
    {
        return $this->hasMany(TacheGestionProjet::class);
    }

    /**
     * Permet de vérifier si l'édition ou la destruction d'un projet est possible
     * @param Projet $projet
     * @return bool
     */
    public static function checkIfUserCanEditOrDestroy(Projet $projet, $addCheckClotureCondition = false)
    {
        // Si on ne souhaite pas check le statut du PAAT, on considère qu'il est non cloture sinon on check le statut
        $paatNonCloture = $addCheckClotureCondition ? Paat::find($projet->paat_id)->statut != PAAT_STATUT::CLOTURE : true;
        return $projet->structure_id == Auth::user()->structure_id
            && Projet::userCanAccess($projet)
            && $paatNonCloture;
    }

    /**
     * Permet de vérifier si un utilisateur peut consulter un projet
     * @param Projet $projet
     * @return bool
     */
    private static function userCanAccess(Projet $projet)
    {
        switch (Auth::user()->nom_role()) {
            case ROLE::DIRECTEUR :
                return $projet->direction_id == Auth::user()->direction_id
                    || MembreProjet::where('projet_id', $projet->id)->where('user_id', Auth::user()->getAuthIdentifier())->exists();
            case ROLE::ACHETEUR :
                return $projet->owner_id == Auth::user()->getAuthIdentifier()
                    || MembreProjet::where('projet_id', $projet->id)->where('user_id', Auth::user()->getAuthIdentifier())->exists();
            case ROLE::EQUIPE_PROJET :
                return MembreProjet::where('projet_id', $projet->id)->where('user_id', Auth::user()->getAuthIdentifier())->exists();
            default:
                return true;
        }
    }


    public function planification()
    {
        $planification = [];

        foreach($this->taches as $tache) {
            array_push($planification, [
                'name' => $tache->nom,
                'desc' => $tache->responsable->nom_complet(),
                'values' => array([
                    'from' => $tache->date_debut,
                    'to' => $tache->date_fin,
                    'label' => $tache->description . ' (' . $tache->nb_jours . ' jour(s))',
                    'customClass' => 'ganttGreen'
                ])
            ]);
        }

        return $planification;
    }
}
