<?php
/*
    Desarrollador: Ing. Jean Jairo Benitez Meza
    Ultima Modificación: 11/04/2023
    Módulo: Formularios Dinámicos
*/
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Controllers\ResponseController;
use App\Http\Controllers\EncryptionController;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class DynamicFormController extends Controller
{
    private $responseController;
    private $encController;

    public function __construct(){
        $this->responseController = new ResponseController();
        $this->encController = new EncryptionController();
    }

    // Obtener formularios
    public function getForm($line){
        try{
            $res = DB::table('S002V01TFODI')
                ->where('FODI_NULI', '=', $line)
                ->join('S002V01TMODU', 'MODU_IDMO', '=', 'FODI_IDMO')
                ->get([
                    'FODI_NUFO AS CODIGO_FORM',
                    'FODI_TIRE AS TITULO_REGISTRO',
                    'FODI_TIMO AS TITULO_MODIFICACION',
                    'MODU_NOMO AS MODULO',
                    'FODI_FERE AS FECHA_REG',
                    'FODI_FEMO AS FECHA_MOD',
                    'FODI_ESTA AS ESTADO',
                    'FODI_WOFL AS WORKFLOW'
                ]);
        } catch (\Throwable $th) {
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_GET000: No se pudo realizar la consulta a la base.", [], 500);
        }
        return $this->responseController->makeResponse(false, "ÉXITO", $res);
    }

    // Obtener un formulario especifico para editar los datos del formulario
    public function getDataForm($codigoForm, $line){
        try{
            $resp = DB::table('S002V01TFODI')->where('FODI_NUFO', $codigoForm)
                ->where('FODI_NULI', '=', $line)
                ->join('S002V01TMODU', 'FODI_IDMO', '=', 'MODU_IDMO')
                ->first(['FODI_NUFO','FODI_TIRE','FODI_TIMO','FODI_DAFO', 'FODI_WOFL','MODU_IDMO','MODU_NOMO']);
        } catch (\Throwable $th) {
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_GET000: No se pudo realizar la consulta a la base.", [], 500);
        }

        if(empty($resp)) return $this->responseController->makeResponse(true, "ERR_DYNFORM_GET001: El código " . $codigoForm . " no existe.", [], 500);

        $objResponse = [
            "CODIGO_FORM" => $resp->FODI_NUFO,
            "TITULO_REGISTRO" => $resp->FODI_TIRE,
            "TITULO_MODIFICACION" => $resp->FODI_TIMO,
            "IDMODULO" => $resp->MODU_IDMO,
            "MODULO" => $resp->MODU_NOMO,
            "WORKFLOW" => $resp->FODI_WOFL,
            "DATA_FORM" => json_decode($resp->FODI_DAFO),
        ];
        return $this->responseController->makeResponse(false, "ÉXITO", $objResponse);
    }

    // Obtener formularios con Workflow
    public function getFormWorkflow($line){
        try{
            $arrForms = DB::table('S002V01TFODI')
                ->where('FODI_ESTA', '=', 'Activo')
                ->where('FODI_NULI', '=', $line)
                ->where('FODI_WOFL', '=', 'PARA WORKFLOW')
                ->get(['FODI_NUFO AS CODIGO_FORM', 'FODI_TIRE AS TITULO_REGISTRO', 'FODI_TIMO AS TITULO_MODIFICACION', 'FODI_DAFO AS DATA_FORM']);
        } catch (\Throwable $th) {
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_GET000: No se pudo realizar la consulta a la base.", [], 500);
        }

        $arrResponse = array();
        foreach ($arrForms as $form) {
            $arrResponse[] =  [
                'CODIGO_FORM' => $form->CODIGO_FORM,
                'NOMBRE_FORM' => $form->NOMBRE_FORM,
                'DATA_FORM' => json_decode($form->DATA_FORM)
            ];
        }
        return $this->responseController->makeResponse(false, "ÉXITO: Consulta Exitosa", $arrResponse);
    }

    // Habilitar un workflow a formulario
    public function enableFormWorkflow(Request $request, $numberForm){
        $validator = Validator::make($request->all(), [
            'USUARIO' => 'required|string',
            'NUMERO_LINEA' => 'required|integer',
        ]);
        if ($validator->fails()) {
            return $this->responseController->makeResponse(
                true,
                "ERR_DYNFORM_ENA000: Se encontraron uno o más errores.",
                $this->responseController->makeErrors($validator->errors()->messages()),
                401
            );
        }

        DB::beginTransaction();
        $response = $request->all();

        try {
            $usuario = $this->encController->decrypt($response['USER']);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_ENA001: Ocurrió un error al desencriptar los datos.", [], 401);
        }

        try{
            $validateExist = DB::table('S002V01TFODI')->where('FODI_NUFO', $numberForm)->exists();
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_ENA002: No se pudo realizar la consulta a la base.", [], 500);
        }
        if(!$validateExist) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_ENA003: No se pudo encontrar el formulario seleccionado.", [], 500);
        }

        $arrUpdate = [
            'FODI_WOFL' => 'CON WORKFLOW',
            'FODI_USMO' => $usuario,
            'FODI_FEMO' => Carbon::now()->timezone('America/Mazatlan')->toDateTimeString(),
            'FODI_FEAR' => DB::raw('CURRENT_TIMESTAMP')
        ];
        try{
            $validateInsert = DB::table('S002V01TFODI')->where('FODI_NUFO', $numberForm)->update($arrUpdate);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_ENA004: No se pudo realizar la modificación en la base.", $th, 500);
        }

        if (!$validateInsert) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_ENA003: No se pudo realizar la modificación en la base." [], 500);
        }

        DB::commit();
        return $this->responseController->makeResponse(false, "ÉXITO: Modificación Exitosa");

    }

    // Consulta de datos para un select de formulario
    public function getDataSelect(Request $request){
        $validator = Validator::make($request->all(), [
            'table' => 'required|string|max:50',
            'column' => 'required|string|max:50',
        ]);
        if ($validator->fails()) {
            return $this->responseController->makeResponse(
                true,
                "ERR_DYNFORM_GET000: Se encontraron uno o más errores.",
                $this->responseController->makeErrors($validator->errors()->messages()),
                401
            );
        }

        DB::beginTransaction();
        $response = $request->all();

        $arrResponseData = $this->getPrimaryKeyData($response['table']);
        if($arrResponseData['error']) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, $arrResponseData['msg'], [], 500);
        }
        $columnName = $arrResponseData['response']->COLUMN_NAME;

        try{
            $arrGetData = DB::table($response['table'])->get([ $columnName.' AS valor', $response['column']. ' AS opcion' ]);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_GET001: No se pudo realizar la consulta a la base.", $th, 500);
        }
        DB::commit();
        return $this->responseController->makeResponse(false, "ÉXITO: Consulta Exitosa", $arrGetData);
    }

    // Elminación de un formulario
    public function deleteForm(Request $request){
        $validator = Validator::make($request->all(), [
            'CODIGO_FORM' => 'required|string',
            'USER' => 'required|string',
        ]);
        if ($validator->fails()) {
            return $this->responseController->makeResponse(
                true,
                "ERR_DYNFORM_DEL000: Se encontraron uno o más errores.",
                $this->responseController->makeErrors($validator->errors()->messages()),
                401
            );
        }
        DB::beginTransaction();
        $response = $request->all();
        try{
            $user = $this->encController->decrypt($response['USER']);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL001: No se pudo obtener el usuario.", [], 500);
        }
        try{
            $objForm = DB::table('S002V01TFODI')->where('FODI_NUFO', $response['CODIGO_FORM'])->first();
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL002: No se pudo realizar la consulta a la base.", [], 500);
        }
        if(empty($objForm)) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL003: El codigo ".$response['CODIGO_FORM']." no existe.", [], 500);
        }
        if($objForm->FODI_ESTA == "Eliminado") {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL004: El formulario ya se encuentra eliminado.", [], 500);
        }

        $arrUpdate = [
            "FODI_ESTA" => "Eliminado",
            "FODI_USMO" => $user,
            "FODI_FEMO" => Carbon::now()->timezone('America/Mazatlan')->toDateTimeString(),
            "FODI_FEAR" => DB::raw('CURRENT_TIMESTAMP')
        ];

        try{
            $validateUpdate = DB::table('S002V01TFODI')->where('FODI_NUFO', $response['CODIGO_FORM'])->update($arrUpdate);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL005: No se pudo realizar la modificación en la base.", [], 500);
        }
        if (!$validateUpdate) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_DEL006: No se pudo realizar la modificación en la base.", [], 500);
        }
        DB::commit();
        return $this->responseController->makeResponse(false, "ÉXITO: Eliminación Exitosa");
    }

    // Creación de formulario
    public function createForm(Request $request) {
        $validator = Validator::make($request->all(), [
            'NOMBRE_FORM_REGISTRO' => 'required|string',
            'NOMBRE_FORM_MODIFICACION' => 'required|string',
            'MODULE' => 'required|string',
            'USER' => 'required|string',
            'WORKFLOW' => 'boolean',
            'DATA_FORM' => 'required',
        ]);
        if ($validator->fails()) {
            return $this->responseController->makeResponse(
                true,
                "ERR_DYNFORM_REG000: Se encontraron uno o más errores.",
                $this->responseController->makeErrors($validator->errors()->messages()),
                401
            );
        }

        DB::beginTransaction();

        $response = $request->all();

        try {
            $response['DATA_FORM'] = json_encode($response['DATA_FORM']);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_REG001: Ocurrió un error al desencriptar los datos.", [], 401);
        }

        try {
            $user = $this->encController->decrypt($response['USER']);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_REG002: Ocurrió un error al desencriptar los datos.", [], 401);
        }

        try{
            $validateModule = DB::table('S002V01TMODU')->where('MODU_IDMO', $response['MODULE'])->exists();
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_REG003: No se pudo realizar la consulta a la base.", [], 500);
        }

        if (!$validateModule) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_REG004: El módulo no existe", [], 500);
        }

        $objResponse = [
            'FODI_TIRE' => $response['NOMBRE_FORM_REGISTRO'],
            'FODI_TIMO' => $response['NOMBRE_FORM_MODIFICACION'],
            'FODI_DAFO' => $response['DATA_FORM'],
            'FODI_IDMO' => $response['MODULE'],
            'FODI_WOFL' => $response['WORKFLOW'] ? 'PARA WORKFLOW' : 'NO WORKFLOW',
            'FODI_USRE' => $user,
            'FODI_NULI' => 1,
            'FODI_FERE' => Carbon::now()->timezone('America/Mazatlan')->toDateTimeString(),
            'FODI_FEAR' => DB::raw('CURRENT_TIMESTAMP')
        ];

        try{
            $validateInsert = DB::table('S002V01TFODI')->insert($objResponse);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_REG005: No se pudo realizar la inserción a la base.", [], 500);
        }
        if (!$validateInsert) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_MENU_REG006: No se pudo realizar la inserción en la base.", [], 500);
        }
        DB::commit();
        return $this->responseController->makeResponse(false, "ÉXITO: Registro Exitoso");
    }

    // Modificación de formulario
    public function updateForm(Request $request, $idform){
        $validator = Validator::make($request->all(), [
            'NOMBRE_FORM_REGISTRO' => 'required|string',
            'NOMBRE_FORM_MODIFICACION' => 'required|string',
            'WORKFLOW' => 'boolean',
            'USER' => 'required|string',
            'DATA_FORM' => 'required',
        ]);
        if ($validator->fails()) {
            return $this->responseController->makeResponse(
                true,
                "ERR_DYNFORM_UPD000: Se encontraron uno o más errores.",
                $this->responseController->makeErrors($validator->errors()->messages()),
                401
            );
        }

        DB::beginTransaction();

        $request = $request->all();
        $request['DATA_FORM'] = json_encode($request['DATA_FORM']);
        $user = $this->encController->decrypt($request['USER']);

        try{
            $validateForm = DB::table('S002V01TFODI')->where('FODI_NUFO', $idform)->exists();
        } catch (\Throwable $th) {
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_UPD001: No se pudo realizar la consulta a la base.", [], 500);
        }
        if (!$validateForm) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_UPD002: No se pudo encontrar el formulario seleccionado.", [], 500);
        }

        $arrUpdate = [
            'FODI_TIRE' => $request['NOMBRE_FORM_REGISTRO'],
            'FODI_TIMO' => $request['NOMBRE_FORM_MODIFICACION'],
            'FODI_DAFO' => $request['DATA_FORM'],
            'FODI_WOFL' => $request['WORKFLOW'] ? 'PARA WORKFLOW' : 'NO WORKFLOW',
            'FODI_USMO' => $user,
            'FODI_FEMO' => Carbon::now()->timezone('America/Mazatlan')->toDateTimeString(),
            'FODI_FEAR' => DB::raw('CURRENT_TIMESTAMP')
        ];

        try{
            $validateRegister = DB::table('S002V01TFODI')->where('FODI_NUFO','=', $idform )->update($arrUpdate);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_UPD003: No se pudo realizar la modificación a la base.", [], 500);
        }
        if (!$validateRegister) {
            DB::rollBack();
            return $this->responseController->makeResponse(true, "ERR_DYNFORM_UPD004: No se pudo realizar la modificación de la base.", [], 500);
        }
        DB::commit();
        return $this->responseController->makeResponse(false, "ÉXITO: Modificación Exitosa");
    }

    // Obtener datos de la llave primaria
    private function getPrimaryKeyData($table_name_main): array {

        $databaseName = DB::connection()->getDatabaseName();

        $qry = "SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH AS LENGTH FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA = '".$databaseName."' AND TABLE_NAME = '".$table_name_main."' AND COLUMN_KEY = 'PRI'";
        try{
            $resp = DB::select(DB::raw($qry));
        } catch(\Exception $th) {
            return [
                "error" => true,
                "msg" => "ERR_DYNFORM_GET001: No se pudo realizar la consulta a la base. $qry",
                "response" => []
            ];
        }
        if (empty($resp)) {
            return [
                "error" => true,
                "msg" => "ERR_DYNFORM_REG002: Ocurrió un error con obtener los datos de la llave primaria. $qry",
                "response" => []
            ];
        }
        return [
            "error" => false,
            "msg" => "ÉXITO",
            "response" => $resp[0]
        ];

    }
}
