<?php

namespace App\Http\Controllers\Administration;

use App\Http\Controllers\Administration\ControllerModel\GPS;
use App\Http\Controllers\Controller;
use App\Models\Consolidation;
use App\Models\Structure;
use App\Models\User;
use APPLICATION;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use ROLE as CONSTANT_ROLE;
use Spatie\Permission\Models\Role;
use TEXT;

class StructureController extends Controller
{
    /**
     * 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()
    {
        return view('administration.structures.index', [
            'structures' => Structure::where('nom', '!=', TEXT::SUPER_ADMINISTRATION)->paginate(APPLICATION::ITEMS_PER_PAGE)
        ]);
    }

    /**
     * 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('administration.structures.create', [
            'consolidations' => Consolidation::all()
        ]);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(Request $request)
    {
        $request->validate([
            'nom' => 'required|unique:structures|string|max:255',
            'description' => 'nullable|string|max:255',
            'adresse' => 'required|string|max:255',
            'cp' => 'required|numeric|max:99999',
            'ville' => 'required|string|max:100',
            'consolidation' => 'required|exists:consolidations,id',
            'referentiel' => 'required|string|max:50',
            'type_achat_cout_global' => 'required|integer',
            'nom_administrateur' => 'required|string|max:45',
            'prenom_administrateur' => 'required|string|max:45',
            'email' => 'required|email|max:255|unique:users',
            'password_administrateur' => 'required|between:8,16|confirmed'
        ]);

        $consolidation = Consolidation::find($request->consolidation);
        if (isset($consolidation)) {
            // On récupère la latitude et longitude
            $gps = $this->getLatitudeLongitude($request->adresse . ',' . $request->cp . ',' . $request->ville);

            $structure = Structure::create([
                'nom' => $request->nom,
                'description' => $request->description,
                'adresse' => $request->adresse,
                'cp' => $request->cp,
                'ville' => $request->ville,
                'latitude' => $gps->latitude,
                'longitude' => $gps->longitude,
                'champ_referentiel' => $request->referentiel,
                'type_achat_cout_global' => $request->type_achat_cout_global,
                'active' => true,
                'consolidation_id' => $consolidation->id,
            ]);

            if ($structure) {
                // On génère tous les rôles pour la nouvelle structure
                $this->generateAllRolesAndAssignMinimumPermissions($structure->id);

                // On ajoute l'administrateur
                $administrateur = User::create([
                    'nom' => $request->nom_administrateur,
                    'prenom' => $request->prenom_administrateur,
                    'email' => $request->email,
                    'password' => Hash::make($request->password_administrateur),
                    'structure_id' => $structure->id,
                    'active' => true
                ]);

                if ($administrateur) {
                    $administrateur->assignRole(CONSTANT_ROLE::ADMINISTRATEUR_STRUCTURE);
                    $administrateur->sendEmailVerificationNotification();
                    return redirect()->route('structures.index')->with('success', 'Structure ajoutée avec succès.');
                } else {
                    $structure->delete();
                    return redirect()->route('structures.index')->withErrors('Impossible d\'ajouter la structure.');
                }
            } else {
                return redirect()->route('structures.index')->withErrors('Impossible d\'ajouter la structure.');
            }
        } else {
            abort(404);
        }
    }

    /**
     * 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)
    {
        return view('administration.structures.edit', [
            'structure' => Structure::find($id),
            'consolidations' => Consolidation::all()
        ]);
    }

    /**
     * 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([
            'nom' => "required|unique:structures,nom,$id|string|max:255",
            'description' => 'nullable|string|max:255',
            'adresse' => 'required|string|max:255',
            'cp' => 'required|numeric|max:99999',
            'ville' => 'required|string|max:100',
            'consolidation' => 'required|exists:consolidations,id',
            'referentiel' => 'required|string|max:50',
        ]);

        $structure = Structure::find($id);
        $consolidation = Consolidation::find($request->consolidation);
        if (isset($consolidation) && isset($structure)) {
            // On récupère la latitude et longitude -> Si l'adresse à été modifiée
            if ($request->adresse != $structure->adresse
                || $request->cp != $structure->cp
                || $request->ville != $structure->ville) {
                $gps = $this->getLatitudeLongitude($request->adresse . ',' . $request->cp . ',' . $request->ville);
            }

            $structure->update([
                'nom' => $request->nom,
                'description' => $request->description,
                'adresse' => $request->adresse,
                'cp' => $request->cp,
                'ville' => $request->ville,
                'latitude' => isset($gps) ? $gps->latitude : $structure->latitude,
                'longitude' => isset($gps) ? $gps->longitude : $structure->longitude,
                'consolidation_id' => $consolidation->id,
                'champ_referentiel' => $request->referentiel
            ]);

            return redirect()->route('structures.index')->with('success', 'Structure mise à jour avec succès.');
        } else {
            abort(404);
        }
    }

    /**
     * Permet de désactiver ou activer uen structure
     * @param $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function active($id)
    {
        $structure = Structure::find($id);
        if (isset($structure)) {
            $structure->update(['active' => !$structure->active]);
            // On applique l'activation ou désactivation aux utilisateurs de la structure
            User::where('structure_id', $structure->id)->update(['active' => $structure->active]);

            return $structure->active ?
                redirect()->route('structures.index')->with('success', 'Structure activée avec succès.')
                : redirect()->route('structures.index')->with('success', 'Structure désactivée avec succès.');
        } else {
            abort(404);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }

    /**
     * Permet de générer les rôles utilisateurs pour une nouvelle structure
     * @param $structure_id
     */
    private function generateAllRolesAndAssignMinimumPermissions($structure_id)
    {
        // Création de l'administrateur
        $admin = Role::create(['name' => CONSTANT_ROLE::ADMINISTRATEUR_STRUCTURE . '_' . $structure_id]);
        $admin->givePermissionTo('see_parametre');
        $admin->givePermissionTo('add_parametre');
        $admin->givePermissionTo('edit_parametre');
        $admin->givePermissionTo('delete_parametre');
        $admin->givePermissionTo('see_utilisateur');
        $admin->givePermissionTo('add_utilisateur');
        $admin->givePermissionTo('edit_utilisateur');
        $admin->givePermissionTo('delete_utilisateur');
        $admin->givePermissionTo('see_structure');
        $admin->givePermissionTo('edit_structure');
        $admin->givePermissionTo('importer_parametre');
        // Création des autres roles
        Role::create(['name' => CONSTANT_ROLE::ACHETEUR . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::CONTROLEUR_GESTION . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::RESPONSABLE_ACHAT . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::CHEF_PROJET . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::DIRECTEUR_ACHAT . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::EQUIPE_PROJET . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::EXPERT . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::DIRECTEUR . '_' . $structure_id]);
        Role::create(['name' => CONSTANT_ROLE::RESPONSABLE_PERFORMANCE_ARS . '_' . $structure_id]);
    }

    private function getLatitudeLongitude($adresse)
    {
        $gps = new GPS();

        $context = stream_context_create(
            array(
                "http" => array(
                    "header" => "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
                )
            )
        );

        // file_get_content retourne un E_warning si il y a une erreur donc on la gère manuellement
        set_error_handler(function () { /* ignore errors */ });
        $content = file_get_contents("https://nominatim.openstreetmap.org/search?format=json&q=" . $adresse, false, $context);

        if ($content) {
            $json = json_decode($content);
            if (isset($json[0])) {
                // On retourne le premier élément du tableau de resultat car c'est le plus pertinant.
                $gps->latitude = $json[0]->lat;
                $gps->longitude = $json[0]->lon;
            }
        }

        restore_error_handler();
        return $gps;
    }
}
