<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Persona;
use App\Models\UserMonitoreo;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use DB;
use Validator;

class AuthController extends Controller
{
    private function photoUrl(?string $photoPath): ?string
    {
        if (!$photoPath) {
            return null;
        }

        if (preg_match('/^https?:\/\//', $photoPath)) {
            return $photoPath;
        }

        return asset(ltrim($photoPath, '/'));
    }

    private function userPhotoPayload($user): array
    {
        if (!$user || !$user->user_per_cod) {
            return [
                'per_foto' => null,
                'per_foto_url' => null,
            ];
        }

        $persona = Persona::select('per_foto')->where('per_cod', $user->user_per_cod)->first();

        return [
            'per_foto' => $persona?->per_foto,
            'per_foto_url' => $this->photoUrl($persona?->per_foto),
        ];
    }

    /**
     * Register a User.
     *
     * @return \Illuminate\Http\JsonResponse
     */

    public function register()
    {
        /*$validator = Validator::make(request()->all(), [
            'name' => 'required',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:8',
        ]);

        if($validator->fails()){
            return response()->json($validator->errors()->toJson(), 400);
        }

        $user = new User;
        $user->name = request()->name;
        $user->email = request()->email;
        $user->password = bcrypt(request()->password);
        $user->save();

        return response()->json($user, 201);*/
        $personal = Persona::select('personas.per_cod', 'personas.per_foto', DB::raw("CONCAT(grados.grad_abrev,' ',especialidades.espe_abrev,' ',personas.per_nombres,' ',personas.per_apaterno,' ',personas.per_amaterno) AS persona"), 'personas.per_ci', 'users.id as user_id', 'users.user_uni_cod as useruni_uni_cod', 'users.passwordapi', 'unidades.uni_detalle', 'roles.name as role')
            ->leftJoin('persona_grados AS pg', function ($join) {
                $join->on('pg.pergrad_per_cod', '=', 'personas.per_cod')
                    ->where('pg.pergrad_estado', '=', 'A');
            })
            ->leftJoin('grados', 'grados.grad_cod', '=', 'pg.pergrad_grad_cod')
            ->leftJoin('persona_especialidades AS pe', function ($join) {
                $join->on('pe.perespe_per_cod', '=', 'personas.per_cod')
                    ->where('pe.perespe_estado', '=', 'A');
            })
            ->leftJoin('especialidades', 'especialidades.espe_cod', '=', 'pe.perespe_espe_cod')
            ->join('users', 'users.user_per_cod', '=', 'personas.per_cod')
            //->join('user_unidades','user_unidades.useruni_user_id','=','users.id')
            ->join('unidades', 'unidades.uni_cod', '=', 'users.user_uni_cod')
            ->join('model_has_roles', 'model_has_roles.model_id', '=', 'users.id')
            ->join('roles', 'roles.id', '=', 'model_has_roles.role_id')
            ->where('roles.name', 'Personal')
            ->where('personas.per_ci', request()->ci)
            //->where('users.id',auth('api')->user()->id)
            ->where('personas.per_estado', 'A')->first();
        //return response()->json($personal, 201);
        if ($personal) {
            $msj = "exito";
            $user = User::where('user_per_cod', $personal->per_cod)->where('user_uni_cod', $personal->useruni_uni_cod)->where('id', $personal->user_id)->first();
            $user->state = true;
            $user->msj = $msj;
            $user->persona = $personal->persona;
            $user->unidad = $personal->uni_detalle;
            $user->passwordapi = $personal->passwordapi;
            $user->role = $personal->role;
            $user->per_foto = $personal->per_foto;
            $user->per_foto_url = $this->photoUrl($personal->per_foto);
            return response()->json($user, 201);
        } else {
            $msj = "Falta asignar unidad, por favor contactese con el responsable de la unidad.";
            $user = new User;
            $user->id = null;
            $user->name = null;
            $user->email = null;
            $user->email_verified_at = null;
            $user->created_at = null;
            $user->updated_at = null;
            $user->user_uni_cod = null;
            $user->user_per_cod = null;
            $user->state = false;
            $user->msj = $msj;
            $user->persona = null;
            $user->unidad = null;
            $user->passwordapi = null;
            $user->role = null;
            return response()->json($user, 201);
        }
        //$volun = Voluntario::where('volun_celular',request()->volun_celular)->first();
        return response()->json($user, 201);
    }


    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        /*$credentials = request(['email', 'password']);

        if (! $token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);*/

        $login = request()->email ?? request()->name;

        $password = request()->password;

        if (!$login || !$password) {
            return response()->json([
                'error' => 'Faltan credenciales'
            ], 400);
        }

        $field = filter_var($login, FILTER_VALIDATE_EMAIL)
            ? 'email'
            : 'name';

        $credentials = [
            $field => $login,
            'password' => $password,
            'state' => 1,
        ];

        if (!$token = auth()->attempt($credentials)) {
            return response()->json([
                'error' => 'Unauthorized'
            ], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        $user = auth()->user();
        $user->must_change_password = !empty($user->passwordapi);
        $photoPayload = $this->userPhotoPayload($user);
        $user->per_foto = $photoPayload['per_foto'];
        $user->per_foto_url = $photoPayload['per_foto_url'];
        $csrfToken = bin2hex(random_bytes(32));
        $user->csrf_token = $csrfToken;

        return $this->withCsrfCookie(response()->json($user), $csrfToken);
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

        return response()->json(['message' => 'Successfully logged out'])
            ->withCookie(cookie()->forget('token', '/', config('session.domain')))
            ->withCookie(cookie()->forget('XSRF-TOKEN', '/', config('session.domain')));
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth()->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        $mustChangePassword = !empty(auth()->user()->passwordapi);

        if (auth()->user()->role->name == 'Personal') {
            $personal = Persona::select('personas.per_cod', 'personas.per_foto', DB::raw("CONCAT(grados.grad_abrev,' ',especialidades.espe_abrev,' ',personas.per_nombres,' ',personas.per_apaterno,' ',personas.per_amaterno) AS persona"), 'personas.per_ci', 'users.id as user_id', 'users.user_uni_cod as useruni_uni_cod', 'users.passwordapi', 'unidades.uni_detalle', 'roles.name as role')
                ->leftJoin('persona_grados AS pg', function ($join) {
                    $join->on('pg.pergrad_per_cod', '=', 'personas.per_cod')
                        ->where('pg.pergrad_estado', '=', 'A');
                })
                ->leftJoin('grados', 'grados.grad_cod', '=', 'pg.pergrad_grad_cod')
                ->leftJoin('persona_especialidades AS pe', function ($join) {
                    $join->on('pe.perespe_per_cod', '=', 'personas.per_cod')
                        ->where('pe.perespe_estado', '=', 'A');
                })
                ->leftJoin('especialidades', 'especialidades.espe_cod', '=', 'pe.perespe_espe_cod')
                ->join('users', 'users.user_per_cod', '=', 'personas.per_cod')
                //->join('user_unidades','user_unidades.useruni_user_id','=','users.id')
                ->join('unidades', 'unidades.uni_cod', '=', 'users.user_uni_cod')
                ->join('model_has_roles', 'model_has_roles.model_id', '=', 'users.id')
                ->join('roles', 'roles.id', '=', 'model_has_roles.role_id')
                ->where('roles.name', 'Personal')
                ->where('personas.per_cod', auth()->user()->user_per_cod)
                //->where('users.id',auth('api')->user()->id)
                ->where('personas.per_estado', 'A')->first();
            return $this->withAuthCookies(response()->json([
                'access_token' => $token,
                'token_type' => 'bearer',
                'expires_in' => auth()->factory()->getTTL() * 60,
                'user_id' => auth()->user()->id,
                'uni_cod' => auth()->user()->user_uni_cod,
                'persona' => $personal->persona,
                'uni_detalle' => $personal->uni_detalle,
                'role' => $personal->role,
                'per_foto' => $personal->per_foto,
                'per_foto_url' => $this->photoUrl($personal->per_foto),
                'must_change_password' => $mustChangePassword,
            ]), $token);
        } else {
            $permissions = auth()->user()->role->getAllPermissions()->map(function ($permission) {
                return $permission->name;
            });
            $photoPayload = $this->userPhotoPayload(auth()->user());

            return $this->withAuthCookies(response()->json([
                'access_token' => $token,
                'token_type' => 'bearer',
                'expires_in' => auth()->factory()->getTTL() * 60,
                'user' => [
                    'name' => auth()->user()->name,
                    'email' => auth()->user()->email,
                    'unidad' => auth()->user()->getUnidad(),
                    'role' => [
                        'id' => auth()->user()->role->id,
                        'name' => auth()->user()->role->name
                    ],
                    'per_foto' => $photoPayload['per_foto'],
                    'per_foto_url' => $photoPayload['per_foto_url'],
                    'permissions' => $permissions,
                    'must_change_password' => $mustChangePassword
                ],
            ]), $token);
        }
    }

    private function withAuthCookies(JsonResponse $response, string $token): JsonResponse
    {
        $csrfToken = bin2hex(random_bytes(32));
        $response->setData(array_merge($response->getData(true), [
            'csrf_token' => $csrfToken,
        ]));

        $minutes = auth()->factory()->getTTL();

        return $this->withCsrfCookie(
            $response->withCookie(cookie(
                'token',
                $token,
                $minutes,
                '/',
                config('session.domain'),
                config('session.secure') ?? request()->isSecure(),
                true,
                false,
                config('session.same_site', 'lax')
            )),
            $csrfToken,
            $minutes
        );
    }

    private function withCsrfCookie(JsonResponse $response, string $csrfToken, ?int $minutes = null): JsonResponse
    {
        return $response->withCookie(cookie(
            'XSRF-TOKEN',
            $csrfToken,
            $minutes ?? auth()->factory()->getTTL(),
            '/',
            config('session.domain'),
            config('session.secure') ?? request()->isSecure(),
            false,
            false,
            config('session.same_site', 'lax')
        ));
    }

    public function changePassword()
    {
        $validator = Validator::make(request()->all(), [
            'current_password' => 'required',
            'password' => 'required|string|min:8|confirmed',
        ], [
            'current_password.required' => 'Ingrese su contraseña actual.',
            'password.required' => 'Ingrese la nueva contraseña.',
            'password.min' => 'La nueva contraseña debe tener al menos 8 caracteres.',
            'password.confirmed' => 'La confirmación de contraseña no coincide.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 422,
                'errors' => $validator->errors(),
            ], 422);
        }

        $user = auth()->user();

        if (!Hash::check(request()->current_password, $user->password)) {
            return response()->json([
                'message' => 422,
                'message_text' => 'La contraseña actual no es correcta.',
            ], 422);
        }

        $user->password = bcrypt(request()->password);
        $user->passwordapi = null;
        $user->save();

        return response()->json([
            'message' => 200,
            'message_text' => 'Contraseña actualizada correctamente.',
        ]);
    }


    /*
|--------------------------------------------------------------------------
| OPERACIONES VIGENTES ASIGNADAS AL MILITAR
|--------------------------------------------------------------------------
|
| Consulta destinada a la aplicación Android.
| Solo devuelve operaciones del usuario autenticado.
| No modifica registros de PostgreSQL.
|--------------------------------------------------------------------------
*/
    public function misOperacionesMovil(Request $request)
    {
        $usuario = auth()->user();

        if (!$usuario) {
            return response()->json([
                'message' => 'Usuario no autenticado.',
            ], 401);
        }

        // Fecha oficial de consulta para Bolivia.
        $hoy = \Carbon\Carbon::now('America/La_Paz')
            ->toDateString();

        $operaciones = \Illuminate\Support\Facades\DB::table(
            'misione_items as mi'
        )
            ->join(
                'misiones as m',
                'm.mision_cod',
                '=',
                'mi.mitem_mision_cod'
            )
            ->join(
                'puestos as p',
                'p.puesto_cod',
                '=',
                'm.mision_puesto_cod'
            )
            ->where(
                'mi.mitem_user_id',
                $usuario->id
            )
            ->where(
                'mi.mitem_estado',
                'A'
            )
            ->where(
                'm.mision_estado',
                'A'
            )
            ->where(
                'p.puesto_estado',
                'A'
            )
            ->whereDate(
                'm.mision_fecha',
                '<=',
                $hoy
            )
            ->whereDate(
                'm.mision_fechafin',
                '>=',
                $hoy
            )
            ->select(
                'm.mision_cod',
                'm.mision_descrip',
                'm.mision_puesto_cod',
                'p.puesto_detalle',
                'm.mision_fecha',
                'm.mision_fechafin'
            )
            ->distinct()
            ->orderBy('m.mision_descrip')
            ->get();

        return response()->json([
            'fecha_actual' => $hoy,
            'total' => $operaciones->count(),
            'operaciones' => $operaciones,
        ]);
    }

    public function savemonitoreo(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'latitud' => ['required', 'numeric', 'between:-90,90'],
            'longitud' => ['required', 'numeric', 'between:-180,180'],
            'uni_cod' => ['nullable', 'integer', 'exists:unidades,uni_cod'],
        ], [
            'latitud.required' => 'La latitud es obligatoria.',
            'latitud.numeric' => 'La latitud debe ser numerica.',
            'latitud.between' => 'La latitud debe estar entre -90 y 90.',
            'longitud.required' => 'La longitud es obligatoria.',
            'longitud.numeric' => 'La longitud debe ser numerica.',
            'longitud.between' => 'La longitud debe estar entre -180 y 180.',
            'uni_cod.exists' => 'La unidad enviada no existe.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 422,
                'errors' => $validator->errors(),
            ], 422);
        }

        $user = auth()->user();
        $unidadCodigo = $user->user_uni_cod ?: $request->uni_cod;

        if (!$unidadCodigo) {
            return response()->json([
                'message' => 422,
                'message_text' => 'El usuario no tiene una unidad asignada para registrar monitoreo.',
            ], 422);
        }

        $usermonitoreo = new UserMonitoreo;
        $usermonitoreo->umoni_uni_cod = $unidadCodigo;
        $usermonitoreo->umoni_user_id = $user->id;
        $usermonitoreo->umoni_latitud = $request->latitud;
        $usermonitoreo->umoni_longitud = $request->longitud;
        $usermonitoreo->umoni_fechahora = Date('Y-m-d H:i:s');
        $usermonitoreo->umoni_estado = 'A';
        $usermonitoreo->umoni_fechareg = Date('Y-m-d');
        $usermonitoreo->umoni_usuareg = $user->id;
        $usermonitoreo->save();

        return response()->json($usermonitoreo);
    }
}
