<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller;

// {} Modelos

// ! Usuario
use App\Models\Usuario;

// {} Librerías

// ! Petición
use Illuminate\Http\Request;

// ! Base de datos
use Illuminate\Support\Facades\DB;

// ! Correo
use Illuminate\Support\Facades\Mail;

// ! Utilidades

// + Correo
use App\Correo;

// {} Clase
class Controlador extends Controller {

  public function autenticacion(Request $request) {

    $api = $request->is('api/*');

    if ($request->routeIs('autenticacion.cerrar')) {

      session()->flush();

      auth()->logout();

      return redirect()->route('inicio');

    }

		if (!$request->usuario)
			$request->usuario = $request->nombre_usuario
		;

    if (!$request->dispositivo)
      $request->dispositivo = request()->header('User-Agent')
    ;

    if (!$request->origen)
      $request->origen = $api ? 'MÓVIL' : 'WEB'
    ;

    $credenciales = DB::select('EXEC [dbo].[p_traer_conexion_usuario_autenticar] ?, ?, ?, ?', [
      $request->usuario,
      $request->contrasena,
      $request->dispositivo,
      $request->origen
    ])[0];

    if (property_exists($credenciales, 'error'))
      return response([$credenciales], $credenciales->error);
    ;

    config([
      'database.connections.sqlsrv.host' => $credenciales->hospedaje,
      'database.connections.sqlsrv.port' => $credenciales->puerto,
      'database.connections.sqlsrv.database' => $credenciales->base_datos,
      'database.connections.sqlsrv.username' => $credenciales->usuario,
      'database.connections.sqlsrv.password' => $credenciales->contrasena
    ]);

    DB::purge();

    DB::reconnect();

    session()->put('conexion', $credenciales);

    // $request['correo_destino'] = 'justininfotep@gmail.com';
    // $request['asunto'] = 'Prueba';
		// $request['tipo_correo'] = 'hola';
    // $request['cuerpo'] = '<p style="margin: 0; font-size: 14px; text-align: center; mso-line-height-alt: 16.8px; color: #fff; background-color: #f68826""><span style="font-size: 16px; caret-color: #fff;"><strong>INFORMACIÓN DEL SERVICIO SOLICITADO</strong></span></p><p style="margin: 0; font-size: 10px; text-align: center; mso-line-height-alt: 16.8px; margin-top: 10px; padding-left: 30px; padding-right: 30px"><span style="font-size: 12px; color: #005cac;"><strong>USUARIO</strong>: MACIEL HILARIO</span></p><p style="margin: 0; font-size: 10px; text-align: center; mso-line-height-alt: 16.8px; margin-top: 10px; padding-left: 30px; padding-right: 30px"><span style="font-size: 12px; color: #005cac;"><strong>CONCEPTO</strong>: LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. VIVAMUS CONGUE, JUSTO VEL ACCUMSAN EFFICITUR, LIGULA LECTUS TINCIDUNT NULLA, SED ELEIFEND LIGULA LIGULA UT IPSUM. DONEC NEC LACINIA ERAT. PRAESENT PULVINAR, JUSTO VITAE LUCTUS PORTTITOR, DOLOR LECTUS MATTIS LEO, SIT AMET EFFICITUR LIGULA PURUS VEL LECTUS. VIVAMUS POSUERE, LIGULA SED SCELERISQUE SOLLICITUDIN, LIGULA LEO DIGNISSIM LIGULA, A EGESTAS ODIO LEO A LECTUS. PROIN PORTTITOR CONGUE TELLUS ET ULTRICES. DONEC ID LACUS SEMPER, CONDIMENTUM EX IN, LUCTUS ARCUI. VESTIBULUM BIBENDUM SIT AMET TORTOR EU INTERDUM. VESTIBULUM FEUGIAT PORTTITOR JUSTO, ET TEMPUS DIAM VENENATIS SED. SED TRISTIQUE VENENATIS URNA, A PORTTITOR TELLUS VIVERRA IN. VESTIBULUM ORNARE AC LECTUS AT DICTUM. PROIN LUCTUS TINCIDUNT LIBERO, AT PORTTITOR NISL LAOREET AC. MORBI VELIT EX, VIVERRA AT ALIQUAM SIT AMET, TINCIDUNT NON ANTE.</span></p>';
    // Mail::to($request->correo_destino)->send(
		// 	new Correo($request)
    // );

    $credenciales = Usuario::where([
      ['usuario', $request->usuario],
      ['contrasena', $request->contrasena]
    ])->first();

    $mantener = $request->has('mantener');

    // auth()->login($credenciales, $mantener);
    auth()->login($credenciales);

    session()->put('usuario', $credenciales);

    session()->put($this->sesion($request));

    return response()->json(session()->all(), 200);

  }

  public function esquema(Request $request) {

    $entidad = (object) [
        'esquema' => $request-> esquema ?? 'dbo',
        'nombre' =>
          $request->funcion ??
          $request->procedimiento ??
          $request->tabla,
        'sentencia' => $request->funcion || $request->procedimiento
          ? "
            SELECT
              ordinal_position AS posicion,
              data_type AS tipo,
              REPLACE(parameter_name, '@', '') AS nombre,
              character_maximum_length AS cantidad_maxima_caracteres
            FROM
              information_schema.parameters
            WHERE
              specific_schema = ? AND
              specific_name = ? AND
							ordinal_position > 0
            ORDER BY
              ordinal_position
            "
          : "
            SELECT
              ordinal_position AS posicion,
              data_type AS tipo,
              column_name AS nombre,
              column_default AS valor_predeterminado,
              CONVERT(BIT, CASE is_nullable WHEN 'YES' THEN 1 ELSE 0 END) AS valor_nulo,
              character_maximum_length AS longitud_maxima_caracteres
            FROM
              information_schema.columns
            WHERE
              table_schema = ? AND
              table_name = ?
            "
    ];

    if (!$entidad->nombre)
      return abort(422)
    ;

    return DB::select($entidad->sentencia, [$entidad->esquema, $entidad->nombre]);

  }

  public function ejecutar(Request $request) {

    $api = $request->is('api/*');

    $entidad = (object) [
			'esquema' => $request-> esquema ?? 'dbo',
			'nombre' => $request->procedimiento ?? $request->funcion,
			'parametros' => $this->esquema($request)
    ];

		$peticion = (object) [
			'parametros' => null,
			'ataduras' => null,
			'consulta' => null,
			'datos' => null
		];

    if (empty($entidad->parametros))
      return abort(422)
    ;

    foreach ($entidad->parametros as $indice => $parametro) {

			$parametro->posicion = intval($parametro->posicion);

      if ($parametro->cantidad_maxima_caracteres) {

        $parametro->cantidad_maxima_caracteres =
          intval($parametro->cantidad_maxima_caracteres)
        ;

        $parametro->cantidad_maxima_caracteres === -1 && $parametro->cantidad_maxima_caracteres = null;

      }

			if (
				$parametro->posicion === 1 &&
				strpos($parametro->nombre, 'id_usuario') === 0 &&
				!$request[$parametro->nombre]
			)
				$request[$parametro->nombre] = session('usuario')->id_usuario
			;

      switch ($parametro->tipo) {

        case 'bit':
          $request[$parametro->nombre] =
            boolval($request[$parametro->nombre])
          ;
        break;

        case 'int':
          $request[$parametro->nombre] =
            intval($request[$parametro->nombre])
          ;
        break;

        case 'decimal':
          $request[$parametro->nombre] = floatval(
            str_replace(',', '', $request[$parametro->nombre])
          );
        break;

        case 'numeric':
          $request[$parametro->nombre] = floatval(
            str_replace(',', '', $request[$parametro->nombre])
          );
        break;

        case 'datetime':
          $request[$parametro->nombre] = date(
            'Y-m-d H:i:s',
            strtotime($request[$parametro->nombre])
          );
        break;

        default:

          if ($request->hasFile($parametro->nombre))
            $request[$parametro->nombre] =
              $request->file($parametro->nombre)->store('archivos/imagenes');
          else if (
            $entidad->nombre !== 'p_registrar_programas' &&
            strpos($parametro->nombre, 'json') === false &&
            strpos($parametro->nombre, 'campo') === false &&
            strpos($parametro->nombre, 'sql') === false
          )
            $request[$parametro->nombre] = strtoupper($request[$parametro->nombre])
          ;

          if (
            strpos($parametro->nombre, 'desde') === 0 ||
            strpos($parametro->nombre, 'hasta') === 0 ||
            strpos($parametro->nombre, 'fecha') === 0
          )
            $request[$parametro->nombre] = str_replace('-', '', $request[$parametro->nombre])
          ;

        break;

      }

      if (
        $request[$parametro->nombre] &&
        $parametro->cantidad_maxima_caracteres &&
        strlen($request[$parametro->nombre]) > $parametro->cantidad_maxima_caracteres
      )
        return response([(object) [
          'mensaje' => strtoupper("
            ¡El campo [$parametro->nombre] no puede exceder de [$parametro->cantidad_maxima_caracteres] digitos!
          "),
          'campo' => $parametro->nombre,
          'codigo_estado' => 400
        ]], 400)
      ;

      $peticion->parametros[] = $request[$parametro->nombre] ?? '';

      $peticion->ataduras[] = '?';

    }

    $peticion->consulta = $request->procedimiento
			? "SET NOCOUNT ON; EXEC $entidad->esquema.$entidad->nombre"
			: "SET NOCOUNT ON; SELECT $entidad->esquema.$entidad->nombre"
		;

    setcookie('Consulta', null, -1);

    if (!$api && session('usuario')->depurador) {

      $parametros = array_map(function($parametro) {

        return (
          !is_int($parametro) &&
          !is_float($parametro)
        )
          ? "'$parametro'"
          : $parametro
        ;

      }, $peticion->parametros);

      setcookie(
        'Consulta',
        $peticion->consulta . implode(', ', $parametros)
      );

    }

		if ($request->retorna ?? true)
			$peticion->datos = $request->procedimiento
				? DB::select(
						$peticion->consulta . ' ' . implode(', ', $peticion->ataduras),
						$peticion->parametros
					)
				: DB::select(
						$peticion->consulta . ' (' . implode(', ', $peticion->ataduras) . ')',
						$peticion->parametros
					)
			;
		else
			$peticion->datos = $request->procedimiento
				? DB::statement(
						$peticion->consulta . ' ' . implode(', ', $peticion->ataduras),
						$peticion->parametros
					)
				: DB::statement(
						$peticion->consulta . '(' . implode(', ', $peticion->ataduras) . ')',
						$peticion->parametros
					)
			;

    $respuesta = response(
      $peticion->datos,
      $peticion->datos[0]?->codigo_estado ?? 200
    );

    return $respuesta;

  }

	public function correo(Request $request) {

		\Log::info($request);

		Mail::to(explode(',', $request->correo_destino))->send(new Correo($request));

		return response()->json();

	}

	public function impresion(Request $request) {

		try {

			$encabezado = DB::select('EXEC [dbo].[p_traer_cabecera_impresion] ?, ?, ?, ?', [session('usuario')->id_usuario, '', '', '']);

			$documento = DB::select('SET NOCOUNT ON; EXEC [dbo].[p_traer_datos_para_impresion] ?, ?, ?, ?, ?, ?',
				[session('usuario')->id_usuario,
				$request->renglon,
				$request->programa,
				$request->id,
				'ENCABEZADO',
				''])
			;

			\Log::info($documento);

			$vista = boolval($request->generico)
				? 'aplicacion.componentes.impresion.pantallas.generica'
				: 'aplicacion.componentes.impresion.pantallas.'. $request->programa
			;

			$html = view($vista, compact('encabezado','request','documento'))->render();

			return response()->json($html);

		} catch (\Throwable $e) {
			\Log::info($e);
			return response()->json('<h1>Hubo un error al momento de la impresión, por favor intente mas tarde.</h1>');
		}

	}

  public function sesion(Request $request) {

    // return response()->json([(object) [
    //   'mensaje' => json_encode(session('programas')->administracion[0]),
    //   'codigo_estado' => 400
    // ]], 400);

    $api = $request->is('api/*');

    if ($api && $request->programa !== 'autenticacion.iniciar')
      session()->put('usuario', (object) ['id_usuario' => $request->id_usuario]);
    ;

    $usuario = Usuario::where('id_usuario', session('usuario')->id_usuario)->first();

    $sesion = [
      'usuario' => $usuario,
      'modulos' => DB::select('EXEC [dbo].[p_traer_registros_combinados] ?, ?, ?', [$usuario->id_usuario, 'MODULOS', '']),
      'programas' => [
        'registros' => [],
        'procesos' => [],
        'reportes' => [],
        'favoritos' => [],
        'genericos' => []
      ],
      'empresa' => DB::select('EXEC [dbo].[p_traer_datos_generales_inicio_sesion] ?, ?, ?', [$usuario->id_usuario, '', ''])
    ];

    foreach (
      DB::select('EXEC [dbo].[p_traer_configuraciones] ?, ?, ?', [$usuario->id_usuario, '', '']) AS $indice => $configuracion
    )
      $sesion['configuracion'][$configuracion->campo] = $configuracion->valor
    ;

    if (count($sesion['empresa']))
      $sesion['empresa'] = $sesion['empresa'][0]
    ;

    foreach (DB::select('EXEC p_traer_programas ?, ?, ?, ?', [$usuario->id_usuario, 'ASIGNADOS', '', 0]) as $indice => $programa) {

      switch ($programa->tipo_programa) {

        case 'R': $programa->tipo_programa = 'registros'; break;

        case 'P': $programa->tipo_programa = 'procesos'; break;

        case 'C': $programa->tipo_programa = 'reportes'; break;

        default: $programa->tipo_programa = null; break;

      }

      if ($api) {

        if ($programa->aplicacion_movil && $programa->tipo_programa) {

          $sesion['programas'][$programa->tipo_programa][] = $programa;

          $programa->favorito &&
          $sesion['programas']['favoritos'][$programa->tipo_programa][] = $programa;

        }

      } else {

        if ($indice === 0)
          $sesion['aplicacion']['rutas'] = array_keys(app('router')->getRoutes()->getRoutesByName()) ?? []
        ;

        if ($programa->tipo_programa && in_array($programa->programa, $sesion['aplicacion']['rutas'])) {

          $sesion['programas'][$programa->tipo_programa][$programa->id_modulo][] = $programa;

          $programa->favorito &&
          $sesion['programas']['favoritos'][] = $programa;

          $programa->generico &&
          $sesion['programas']['genericos'][] = $programa->programa;

        }

      }

    }

    $sesion['programas']['favoritos'] = [];

    foreach (DB::select('EXEC p_traer_programas ?, ?, ?, ?', [$usuario->id_usuario, 'FAVORITOS', '', 0]) as $indice => $programa) {

      switch ($programa->tipo_programa) {

        case 'R': $programa->tipo_programa = 'registros'; break;

        case 'P': $programa->tipo_programa = 'procesos'; break;

        case 'C': $programa->tipo_programa = 'reportes'; break;

        default: $programa->tipo_programa = null; break;

      }

      if ($api) {

        if ($programa->aplicacion_movil && $programa->tipo_programa)
          $sesion['programas']['favoritos'][$programa->tipo_programa][] = $programa;

      } else if ($programa->tipo_programa && in_array($programa->programa, $sesion['aplicacion']['rutas'])) {

        $programa->referencia = $programa->descripcion;

        $sesion['programas']['favoritos'][] = $programa;

      }

    }

    return $sesion;

  }

}
