<?php

namespace App\Http\Controllers;

use Log;
use Auth;
use Session;
use Exception;
use Carbon\Carbon;
use App\Models\User;
use GuzzleHttp\Client;
use App\Models\api\v1\Role;
use Illuminate\Support\Str;
use App\Helpers\DateHelpers;
use Illuminate\Http\Request;
use App\Models\api\v1\Gender;
use App\Models\api\v1\Country;
use App\Models\api\v1\UserRole;
use App\Models\api\v1\UserSpace;
use Illuminate\Http\JsonResponse;
use App\Helpers\SerializerHelpers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Validator;
use GuzzleHttp\Psr7\Request as Psr7Request;
use SimpleSoftwareIO\QrCode\Facades\QrCode;


class UserController extends Controller
{
    /**
     * get Auth token
     */
    public function login(Request $request)
    {

        //Validate input fields
        $validator = Validator::make(
            $request->all(),
            [
                'username' => 'required|numeric|min:' . env('MSISDN_MIN_LENGTH'),
                'password' => 'required|min:6|numeric',
            ],
            [
                'username.*' => 'Veuillez rentrer un login valide',
                'password.*' => 'Veuillez rentrer un mot de passe valide'
            ]
        );

        // If Errors
        if ($validator->fails()) {
            return $this->ReturnResponse(false, $validator->errors(), [], 401);
        }

        // Delete expired tokens
        try {
            DB::table('oauth_access_tokens')->where('revoked', 1)->Orwhere("expires_at", "<", Carbon::now())->delete();
        } catch (Exception $e) {
            $message = "Suppression token - " . $e->getMessage() . " - line: " . $e->getLine() . " - file: " . $e->getFile();
            // Log Error
            Log::channel('customlog')->error($message);
            return $this->ReturnResponse(false, $message, [], 500);
        }

        //si le compte n existe pas
        if (!$user = User::whereUsername($request->username)->first())
            return $this->ReturnResponse(false, "Ce compte n'existe pas", [], 404);

        // Connect
        try {
            //If user and password valid - Allow Connection
            if (Auth::attempt(['username' => $request->username, 'password' => $request->password])) {
                //init
                $user           = Auth::user();
                $user_token     = $user->createToken('AMCAuthApp');

                //retour formaté depuis commonController
                return $this->ReturnResponse(true, 'User login successful.', ['token' => $user_token->accessToken, 'token_expired_at' => $user_token->token->expires_at], 200);
            } else {
                return $this->ReturnResponse(false, 'Login or Password not correct', [], 401);
            }
        } catch (Exception $e) {
            $message = "token erreur - " . $e->getMessage() . " - line: " . $e->getLine() . " - file: " . $e->getFile();
            //Logging de l erreur
            Log::channel('customlog')->error($message);
            return $this->ReturnResponse(false, $message, [], 500);
        }
    }


    /**
     * Deconnexion
     */
    public function logout()
    {
        //return $this->ReturnResponse(true, "User Disconnected", [], 200);

        if (Auth::check())
        {
            Auth::user()->token()->revoke();
            
            return $this->ReturnResponse(true, "User Disconnected", [], 200);
        }
        return $this->ReturnResponse(false, "User Not Connected", [], 403);
    }


    /**
     * fonction de creation de compte
     */
    public function userCreate(Request $request)
    {
        $validator = Validator::make(
            $request->all(),
            [
                'username'              => 'required|numeric|min:' . env('MSISDN_MIN_LENGTH'),
                'password'              => 'min_digits:4|numeric|required_with:password_confirmation|same:password_confirmation',
                'password_confirmation' => 'min:4',
                'lastname'              => 'required|min:2',
                'firstname'             => 'required|min:2',
                'country_id'            => 'required|numeric|min:1|exists:countries,id',
                'roles'                 => 'required|array|min:1',
                'roles.*'               => 'required|numeric|distinct|min:1',
                'gender_id'             => 'required|numeric|min:1',
                'phone_code'            => 'required|min:2',
                'roles'                  => 'array|min:1',

            ],
            [
                'username.*'                => 'Veuillez rentrer un login valide',
                'password.*'                => 'Veuillez rentrer un mot de passe correct',
                'password_confirmation.*'   => 'Mot de passe different',
                'lastname.*'                => 'Nom incorrect',
                'firstname.*'               => 'Prénom incorrect',
                'country_id.*'              => 'Pays incorrect',
                'roles.*'                   => 'Role incorrect',
                'phone_code.*'              => 'Indicatif incorrect',
                'gender_id.*'               => 'Genre incorrect',
                'roles.*'                   => 'Role incorrect',
            ]
        );

        // If errors
        if ($validator->fails()) {
            return $this->ReturnResponse(false, $validator->errors(), [], 400);
        }

        //Check gender
        if (!$gender = Gender::Active()->find($request->gender_id))
            return $this->ReturnResponse(false, "Ce genre n'existe pas", [], 404);

        //Check Roles
        if (Role::Active()->whereIn('id', $request->roles)->count() != count($request->roles))
            return $this->ReturnResponse(false, "Un ou plusieurs roles selectionnés n'existe pas", [], 404);

        // Verify username is not already taken
        if ($user = User::whereUsername(trim($request->phone_code) . trim($request->username))->first())
            return $this->ReturnResponse(false, "Ce compte existe déjà", [], 403);

        try
        {
            DB::beginTransaction();
            // Create User
            $current_user = User::create([
                'uuid'          => Str::uuid()->toString(),
                'lastname'      => $request->lastname,
                'firstname'     => $request->firstname,
                'username'      => trim($request->phone_code) . trim($request->username),
                'phone_code'    => $request->phone_code,
                'gender_id'     => $request->gender_id,
                'country_id'    => $request->country_id,
                'password'      => Hash::make($request->password), //bcrypt($request->password)
                //'created_by'    => 1, // @TODO Update with Session for API Key
                'created_at'    => date("Y-m-d H:i:s"),
            ]);

            // Create Role
            foreach ($request->roles as $role) {
                UserRole::create([
                    "user_id" => $current_user->id,
                    "role_id" => $role
                ]);
            }

            // Create Token
            $user_token = $current_user->createToken('DigitalTaryAuthApp');

            // Commit Changes
            DB::commit();

            // Return Response
            return $this->ReturnResponse(
                false,
                "User created successfully and logged in",
                ['token' => $user_token->accessToken, 'token_expired_at' => $user_token->token->expires_at, 'roles' => Role::whereIn('id', $request->roles)->get()],
                201
            );

        }
        catch (Exception $e)
        {
            DB::rollBack();
            // Log Error
            $message =  "Creation de compte - impossible de creer le compte " . $e->getMessage() . " - line: " . $e->getLine() . " - username:" . $request->username;
            Log::channel('customlog')->error($message);
            return $this->ReturnResponse(false, $message, [], 500);
        }
    }



    /**
     * Mise a jour phone Number
     */
    public function updatePhoneNumber(Request $request)
    {
        return response()->json(['success' => true, 'message' => 'Numero mise à jour', 'data' => []], 200);
        // validation
        $validator = Validator::make(
            $request->all(),
            [
                'otp' => 'required|numeric|min_digits:4',
                //'new_phone_number' => 'required|numeric|min_digits:'.env('MSISDN_MIN_LENGTH'),
            ],
            [
                'otp.*' => 'Otp incorrect',
                //'new_phone_number.*' => 'Nouveau numero incorrect',
            ]
        );
        //si erreur
        if ($validator->fails()) {
            return  response(['success' => false, 'message' => $validator->errors(), 'data' => []], 400);
        }

        //retour token
        return response()->json(['success' => true, 'message' => 'Numero mise à jour', 'data' => []], 200);
    }


    /**
     * Mise a jour phone Number
     */
    public function deleteAccount(Request $request)
    {
        //retour token
        $validator = Validator::make(
            $request->all(),
            [
                'roles'                 => 'array|min:1',
                'roles.*'               => 'exists:roles,id',
                'delete_account'        => 'required',

            ],
            [
                'delete_account'        => 'Veuillez préciser le mode de suppression',
            ]
        );

        // If errors
        if ($validator->fails()) {
            return $this->ReturnResponse(false, $validator->errors(), [], 400);
        }

        if($request->roles)
        {
            
            auth()->user()->roles()->detach($request->roles);
        }
       
        if($request->delete_account == true)
        {
            auth()->user()->update([
                "is_deleted"  => 1,
                "deleted_at"  => now(),
                "deleted_by"  => auth()->user()->id,
                "is_active"   => 0,
            ]);

            auth()->user()->token()->revoke();
        }

        return response()->json(['success' => true, 'message' => 'Compte supprimé avec success', 'data' => []], 200);

    }

    public function userUpdateProfile(Request $request)
    {
        // validation
        $validator = Validator::make(
            [
                "lastname"                  => $request->lastname,
                "firstname"                 => $request->firstname,
                "gender_id"                 => $request->gender_id
            ],
            [
                'lastname'                  => 'required|min:2',
                'firstname'                 => 'required|min:2',
                'gender_id'                 => 'required|numeric|min:1|exists:genders,id',

            ],
            [
                'lastname.required'         => 'Nom est réquis',
                'lastname.min'              => 'Nom doit avoir au moins deux caractères',
                'firstname.required'        => 'Prénom est réquis',
                'firstname.min'             => 'Prénom doit avoir au moins deux caractères',
                'gender_id.*'               => 'Genre incorrect',
            ]
        );
        // If errors
        if ($validator->fails()) {
            return $this->ReturnResponse(false, $validator->errors(), [], 400);
        }

       
        //Check gender
        if (!Gender::Active()->find($request->gender_id))
            return $this->ReturnResponse(false, "Ce genre n'existe pas", [], 404);

        
        try {
            //creer utilisateur
            User::where('id', auth()->user()->id)->update([
                'lastname'      => $request->lastname,
                'firstname'     => $request->firstname,
                'gender_id'     => $request->gender_id,
            ]);
            //recuperation des info
            $user_update = User::where("id", auth()->user()->id)->first();

            //retour resltat
            return $this->ReturnResponse(true, "Utilisateur mise à jour", SerializerHelpers::serializeUser($user_update));

        }
        catch (Exception $e)
        {
            //Logging de l erreur
            $message =  "Mise a jour de compte de compte - impossible de creer le compte " . $e->getMessage() . " - line: " . $e->getLine() . " - uuid:" . $request->user_uuid;
            \Log::channel('customlog')->error($message);
            return response()->json(
                [
                    'status'  => 401, 
                    'message' =>  $message, 
                    'data'    => []
                ], 
                401
            );
        }

    }

    /**
     * Mise ajour mot de pasgit se
     */
    public function updatePassword(Request $request): JsonResponse
    {
        try
        {
            $validator = Validator::make(
                [
                    "old_password"          => $request->old_password,
                    "password"              => $request->password,
                    "password_confirmation" => $request->password_confirmation,
                ],  
                [
                    'password'              => 'min_digits:4|numeric|required_with:password_confirmation|confirmed',
                    'password_confirmation' => 'min_digits:4',
                    'old_password'          => 'required',
                ],
                [
                    'old_password.*'            => 'Veuillez rentrer l\'ancie mot de passe correct',
                    'password.*'                => 'Veuillez rentrer un mot de passe correct',
                    'password_confirmation.*'   => 'Mot de passe different',
                ]
            );

            //si erreur
            if ($validator->fails())
            {
                return $this->ReturnResponse(false, $validator->errors(), [], 400);
            }

            #Match avec Old Password
            if (!Hash::check($request->old_password, auth('api')->user()->password))
            {
                return $this->ReturnResponse(false, 'Ancien mot de passe non correct', [], 403);
            }

            #Mise a jour
            User::whereId(auth()->user()->id)->update([
                'password' => Hash::make($request->password)
            ]);

            //reponse
             return $this->ReturnResponse(true, 'Mot de passe mise à jour');
        }
        catch (Exception $e)
        {
            //Logging de l erreur
            $message =  "Mise a jour de compte de compte - Error: " . $e->getMessage() . " - line: " . $e->getLine() . " - uuid:" . $request->user_uuid;
            Log::channel('customlog')->error($message);
            return $this->ReturnResponse(true,  $message, [], 401);
        }

    }


    /**
     * Info utilisateur connecté
     */
    public function details(Request $request)
    {
        $user = User::find(auth('api')->user()->id);
        return $this->ReturnResponse(true, "User Details", SerializerHelpers::serializeUser($user));
    }

    /**
     * Info utilisateur connecté
     */
    public function wifiInfo(Request $request)
    {
        $data = [
            "id" => 7,
            "msisdn" => "0709887766",
            "subscription_formula_id" => 1,
            "subscription_formula_name" => "pass 30mn",
            "subscription_formula_time" => "30;00",
            "remaining_time" => "00:13:33",
            "is_active" => 1,
            "created_at" => "2023-12-24T11:39:37.000000Z",
        ];
        return response()->json(['success' => true, 'data' => $data], 200);
    }

    /**
     * Info compte Flex utilisateur
     */
    public function flexInfo(Request $request)
    {
        $data = [
            "wallet" => [
                "id" => 1,
                "user_id" => 1,
                "country_payment_mode_id" => 1,
                "name" => "Flex",
                "is_active" => 1,
                "user" => [
                    "id" => 1,
                    "uuid" => "8ab3e74a-68a0-4bf9-90cb-7f0981a30274",
                    "gender_id" => 2,
                    "username" => "0709887766",
                    "email" => null,
                    "email_verified_at" => null,
                    "create_time" => "2023-12-24 11:39:37",
                    "lastname" => "Toure",
                    "firstname" => "Al Badra",
                    "phone_code" => "+225",
                    "country_id" => 1,
                    "is_active" => 1,
                ],
                "countries_payment_modes" => [
                    'id' => 1,
                    'country_id' => 2,
                    'payment_mode_id' => 1,
                    'is_active' => 1,
                    'countries' => [
                        'id' => 2,
                        'uuid' => "9008-00999-00-000",
                        'name' => "Burkina Faso",
                        'is_active' => 1,
                    ],
                    'payment_modes' => [
                        'id' => 1,
                        'uuid' => "9008-00999-00-000",
                        'name' => "Flex",
                        'is_active' => 1,
                    ]
                ]
            ],
            "flex_info" => [
                "id" => 7,
                "msisdn" => "0709887766",
                "firstname" => "Jean",
                "lastname" => "Valjean",
                "solde" => 9500,
                "is_active" => 1,
                "created_at" => "2023-12-24T11:39:37.000000Z",
            ]
        ];
        #reponse
        return response()->json(['success' => true, 'data' => $data], 200);
    }



    /**
     * Verifier Otp
     */
    public function checkOtp(Request $request)
    {
        //validation
        $validator = Validator::make(
            [
                "number" => $request->number,
                "otp" => $request->otp,
            ],
            [
                'number' => 'required|numeric|min_digits:' . env('MSISDN_MIN_LENGTH'),
                'otp' => 'required|min_digits:4',
            ],
            [
                'number.*' => 'Numero incorrect',
                'otp.*' => 'Format otp incorrect',
            ]
        );
        if ($validator->fails()) {
            return  response(['code' => 400, 'success' => false, 'message' => $validator->errors()], 400);
        }
        return response()->json(['success' => true, 'message' => "Otp valide"], 200);
    }


    /**
     * send Otp
     */
    public function sendOtp(Request $request)
    {
        $data = 4566;
        return response()->json(['success' => true, 'message' => "Otp Sent", 'data' => []], 200);
    }


    /**
     * Display a listing of the resource.
     */
    public function index(UsersDataTable $dataTable, Request $request)
    {
        if ($request->msg) {
            return $dataTable->render('users.index', [
                'status' => $request->status,
                'msg' => $request->msg
            ]);
        } else {
            return $dataTable->render('users.index');
        }
    }

    /**
     * Display the specified profile.
     */
    public function profile($id)
    {
        $user = User::find($id);
        $cartes = Cartes::where('id_users', $user->id)->first();

        return view('users.profile', [
            'user' => $user,
            'cartes' => $cartes,
        ]);
    }





    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        $user = User::find($id);
        $formattedDate = $user->date_naissance ? Carbon::createFromFormat('d/m/Y', $user->date_naissance)->format('Y-m-d') : null;

        return view('users.edit', [
            'user' => $user,
            'formattedDate' => $formattedDate,

        ]);
    }

    /**
     * Verifcode the form for editing the specified resource.
     */
    public function verifcode(Request $request, string $id)
    {
        $find = UserCode::where('user_id', auth()->user()->id)
            ->where('code', implode("", $request->code))
            ->where('updated_at', '>=', now()->subMinutes(2))
            ->first();

        if (!is_null($find)) {

            DB::table('users')
                ->where('id', $id)
                ->update([
                    'phone' => $request->indicatif . '' . $request->phone,
                    'email' => $request->email,
                    'adresse' => $request->adresse,
                    'lieu_residence' => $request->lieu_residence,
                    'nom' => $request->nom,
                    'prenom' => $request->prenom,
                    'date_naissance' => $request->birthday,
                ]);
        }

        if (auth()->user()->role == 2) {
            return redirect()->route('partenaires.profil');
        }

        return redirect()->route('users.profile', auth()->user());
    }



    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        // Récupérez l'utilisateur actuellement authentifié
        $user = auth()->user();
        //   dd($user->phone);
        $userPhoneWithoutPrefix = substr($user->phone, 4);
        $phone = $request->phone;
        // dd($userPhoneWithoutPrefix);
        // print_r($phone);

        //   dd($requestPhoneWithoutIndicatif);

        // Vérifiez si le numéro de téléphone a été modifié
        if ($userPhoneWithoutPrefix != $phone) {
            // Le numéro de téléphone a été modifié, demandez le code
            return redirect()->route('users.2fa', [
                'id' => $user,
                'phone' => $request->phone,
                'indicatif' => $request->indicatif,
                'email' => $request->email,
                'adresse' => $request->adresse,
                'ville' => $request->ville,
                'nom' => $request->nom,
                'prenom' => $request->prenom,
                'birthday' => $request->birthday,
            ]);
        } else {

            $user->update([

                'nom' => $request->nom,
                'prenom' => $request->prenom,
                'email' => $request->email,
                'adresse' => $request->adresse,
                'ville' => $request->ville,
                'birthday' => $request->birthday,
            ]);
            if (auth()->user()->role == 2) {
                return redirect()->route('partenaires.profil');
            }
            return redirect()->route('users.profile', ['id' => $user->id]);

            return redirect()->route('users.profile', ['id' => $user->id]);
        }

        // Si le numéro de téléphone n'a pas été modifié, procédez à la mise à jour des autres champs

        // Validez les champs en fonction du rôle de l'utilisateur
        $validatorRules = [
            'indicatif' => ['required', 'string', 'max:255'],
            'phone' => ['required', 'string', 'size:10', 'max:255'],
            'nom' => ['required', 'string', 'max:255'],
            'prenom' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'string', 'max:255'],
        ];

        if ($user->role != 2) {
            $validatorRules += [
                'birthday' => ['required', 'string', 'max:255'],
                'adresse' => ['required', 'string', 'max:255'],
                'ville' => ['required', 'string', 'max:255'],
            ];
        }

        $validator = Validator::make($request->all(), $validatorRules, [
            'phone.required' => 'Le tel est obligatoire!',
            'indicatif.required' => 'L\'indicatif est obligatoire !',
            'email.required' => 'L\'email est obligatoire!',
            'email.email' => 'L\'email incorrect!',
            'adresse.required' => 'L\'adresse est obligatoire !',
            'nom.required' => 'Le nom est obligatoire !',
            'prenom.required' => 'Le prénom est obligatoire !',
            'birthday.required' => 'Date de naissance est obligatoire !',
        ]);

        if ($validator->fails()) {
            return redirect()->back()->withInput()->withErrors($validator);
        }

        // Autres traitements et redirections ici...


    }



    /**
     * disable the specified resource from storage.
     */
    public function disable(string $id)
    {
        $user = User::find($id);

        if ($user) {
            $user->actif = 0;
            $user->save();
        }
        return redirect('users/details/' . $user->id);
    }
    /**
     * disable the specified resource from storage.
     */
    public function enable(string $id)
    {
        $user = User::find($id);

        if ($user) {
            $user->actif = 1;
            $user->save();
        }
        return redirect('users/details/' . $user->id);
    }


    //API
    public function myinformation(string $id)
    {
        $user = User::where('id', $id)->get();
        return response()->json(
            $user
        );
    }



    public function resetpassword(Request $request)
    {

        $_phone = $request?->phone;

        $user = User::where('phone', $_phone)->first();

        if (Auth::loginUsingId($user?->id))
        {

            if (auth()->user()->email_verified_at) {
                auth()->user()->generateCode();
            }

            return response()->json([
                'status' => 'success',
                'message' => 'Nous avons envoyé votre code de réinitialisation de mot de passe par sms !'
            ]);
        }

        return response()->json(['error' => 'Vous avez entré un mauvais tel.!'], 401);
    }



    public function verifiecode(Request $request)
    {
        if (!isset($request->phone) || !isset($request->code)) {
            return response()->json(['error' => 'invalid_credentials'], 401);
        }

        $user = User::where('phone', $request->phone)->first();

        if ($user)
        {
            $find = UserCode::where([
                'code'      => $request->code,
                'user_id'   => $user->id,
            ])
                ->where('updated_at', '>=', now()->subMinutes(2))
                ->first();

            if (!is_null($find)) {

                return response()->json([
                    'status'    => 'success',
                    'message'   => 'Votre code est valide',
                ]);
            }
        }

        return response()->json(['error' => 'Vous avez entré un mauvais code.!'], 401);
    }


    /**
     * Function to update roles
     */
    public function updateRoles(Request $request): JsonResponse
    {
        $validator = Validator::make(
            $request->all(),
            [
                'roles'                 => 'required|array|min:1',
                'roles.*'               => 'required|numeric|distinct|min:1',
            ],
            [
                'roles.*'               => 'Role incorrect',
                'roles.*'               => 'Role incorrect',
            ]
        );

        // If errors
        if ($validator->fails())
        {
            return $this->ReturnResponse(false, $validator->errors(), [], 400);
        }

        //Check Roles
        if (Role::Active()->whereIn('id', $request->roles)->count() != count($request->roles))
            return $this->ReturnResponse(false, "Un ou plusieurs roles selectionnés n'existe pas", [], 404);

        try
        {
            DB::beginTransaction();

            UserRole::where([
                "user_id" => auth()->user()->id,
            ])->update(
                [
                    'is_active'     => 0,
                    'is_deleted'    => 1,
                    'deleted_at'    => now(),
                    'deleted_by'    => auth()->user()->id
                ]
            );

            // Create Role
            foreach ($request->roles as $role)
            {
                UserRole::create([
                    "user_id"   => auth()->user()->id,
                    "role_id"   => $role,
                    "is_active" => 1
                ]);
            }

            // Commit Changes
            DB::commit();

            // Return Response
            return $this->ReturnResponse(
                true,
                "User roles updated successfully"
            );

        }
        catch (Exception $e)
        {
            DB::rollBack();
            // Log Error
            $message =  "Creation de compte - impossible de creer le compte " . $e->getMessage() . " - line: " . $e->getLine() . " - username:" . $request->username;
            Log::channel('customlog')->error($message);
            return $this->ReturnResponse(false, $message, [], 500);
        }
    }


}
