<?php
class Empresa
{
    public $id;
    public $codempresa;
    public $principal;
    public $nombreEmpresa;
    public $urlApi;
    public $apiKey;
    public $rubros = [];
    public $modulos = [];
    public $fechaRegistro;

    function __construct()
    {
        !empty($this->fechaRegistro) && $this->fechaRegistro = date("d-m-Y h:i a", strtotime($this->fechaRegistro));
    }

    public static function obtenerTodos(): object
    {
        $db = obtenerConexion();

        $query = "SELECT * FROM sistema.view_empresas WHERE estado = 1 ORDER BY codempresa ASC;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);

        try {
            $stmt->execute();
            $empresas = $stmt->fetchAll(PDO::FETCH_CLASS, __CLASS__);

            return (object)[
                'status' => 200,
                'message' => 'success',
                'data' => $empresas
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage()
            ];
        }
    }

    public function guardar($usuario, $db): object
    {
        if (empty($db)) $db = obtenerConexion();

        $respuesta = null;
        $idEmpresa = null;

        empty($this->urlApi) && $this->urlApi = null;
        empty($this->apiKey) && $this->apiKey = null;

        $query = "EXEC sistema.sp_guardarEmpresa :id,:codempresa,:nombre,:principal,:urlApi,:apiKey,:usuario,:respuesta,:idEmpresa;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
        $stmt->bindParam(':codempresa', $this->codempresa, PDO::PARAM_INT);
        $stmt->bindParam(':nombre', $this->nombreEmpresa, PDO::PARAM_STR);
        $stmt->bindParam(':principal', $this->principal, PDO::PARAM_INT);
        $stmt->bindParam(':urlApi', $this->urlApi, PDO::PARAM_STR);
        $stmt->bindParam(':apiKey', $this->apiKey, PDO::PARAM_STR);
        $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
        $stmt->bindParam(':respuesta', $respuesta, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000);
        $stmt->bindParam(':idEmpresa', $idEmpresa, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 4000);

        try {
            $stmt->execute();

            if ($respuesta == 'success') {
                $this->id = $idEmpresa;

                $stmt->closeCursor();

                $respuestaRubros = $this->guardarRubros($db, $usuario);

                if ($respuestaRubros->status != 200 || ($respuestaRubros->status == 200 && $respuestaRubros->message != 'success')) {
                    return $respuestaRubros;
                }

                $respuestaModulos = $this->guardarModulos($db, $usuario);

                if ($respuestaModulos->status != 200 || ($respuestaModulos->status == 200 && $respuestaModulos->message != 'success')) {
                    return $respuestaModulos;
                }
            }

            return (object)[
                'status' => 200,
                'message' => $respuesta,
                'id' => $idEmpresa
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Guardado de empresa'
            ];
        }
    }

    private function guardarRubros($db, $usuario): object
    {
        $ids = [];

        foreach ($this->rubros as $rubro) {
            $respuesta = null;
            $id = null;
            $query = "EXEC sistema.sp_guardarRubroDeEmpresa :empresa,:id,:rubro,:usuario,:respuesta,:idRubro;";
            $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
            $stmt->bindParam(':empresa', $this->id, PDO::PARAM_INT);
            $stmt->bindParam(':id', $rubro["id"], PDO::PARAM_INT);
            $stmt->bindParam(':rubro', $rubro["idRubro"], PDO::PARAM_STR);
            $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
            $stmt->bindParam(':respuesta', $respuesta, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000);
            $stmt->bindParam(':idRubro', $id, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 4000);

            try {
                $stmt->execute();

                if ($respuesta != 'success') {
                    return (object)[
                        'status' => 500,
                        'message' => $respuesta . ' Guardado de rubros de empresa'
                    ];
                    break;
                }

                $ids[] = $id;
            } catch (PDOException $e) {
                return (object)[
                    'status' => 500,
                    'message' => $e->getMessage() . ' Guardado de rubros'
                ];
                break;
            }
        }

        $strIds = count($ids) > 0 ? implode(',', $ids) : '0';

        $query = "EXEC sistema.sp_limpiarRubrosDeEmpresa :empresa,:rubros;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':empresa', $this->id, PDO::PARAM_INT);
        $stmt->bindParam(':rubros', $strIds, PDO::PARAM_STR);

        try {
            $stmt->execute();
            return (object)[
                'status' => 200,
                'message' => 'success'
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Limpiar rubros'
            ];
        }
    }

    private function guardarModulos($db, $usuario): object
    {
        $ids = [];

        foreach ($this->modulos as $modulo) {
            $respuesta = null;
            $id = null;

            $query = "EXEC sistema.sp_guardarModuloEmpresa :empresa,:id,:modulo,:usuario,:respuesta,:idModulo;";
            $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
            $stmt->bindParam(':empresa', $this->id, PDO::PARAM_INT);
            $stmt->bindParam(':id', $modulo["id"], PDO::PARAM_INT);
            $stmt->bindParam(':modulo', $modulo["idModulo"], PDO::PARAM_STR);
            $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
            $stmt->bindParam(':respuesta', $respuesta, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000);
            $stmt->bindParam(':idModulo', $id, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 4000);

            try {
                $stmt->execute();

                if ($respuesta != 'success') {
                    return (object)[
                        'status' => 500,
                        'message' => $respuesta . ' Guardado de modulos'
                    ];
                    break;
                }

                $ids[] = $id;
            } catch (PDOException $e) {
                return (object)[
                    'status' => 500,
                    'message' => $e->getMessage() . ' Guardado de modulos'
                ];
                break;
            }
        }

        $strIds = count($ids) > 0 ? implode(',', $ids) : '0';

        $query = "EXEC sistema.sp_limpiarModulosEmpresa :empresa,:usuario,:modulos;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':empresa', $this->id, PDO::PARAM_INT);
        $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
        $stmt->bindParam(':modulos', $strIds, PDO::PARAM_STR);

        try {
            $stmt->execute();
            return (object)[
                'status' => 200,
                'message' => 'success'
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Limpiar modulos'
            ];
        }
    }

    public static function obtenerRubros($idEmpresa): object
    {
        $db = obtenerConexion();

        $query = "SELECT * FROM sistema.view_rubrosEmpresa WHERE empresa = :idEmpresa AND estado = 1;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':idEmpresa', $idEmpresa, PDO::PARAM_INT);

        try {
            $stmt->execute();
            $datos = $stmt->fetchAll(PDO::FETCH_OBJ);
            return (object)[
                'status' => 200,
                'message' => 'success',
                'data' => $datos
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Obtener rubros'
            ];
        }
    }

    public static function obtenerModulos($idEmpresa): object
    {
        $db = obtenerConexion();

        $query = "SELECT * FROM sistema.view_modulosEmpresa WHERE empresa = :idEmpresa AND estado = 1;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':idEmpresa', $idEmpresa, PDO::PARAM_INT);

        try {
            $stmt->execute();
            $datos = $stmt->fetchAll(PDO::FETCH_OBJ);
            return (object)[
                'status' => 200,
                'message' => 'success',
                'data' => $datos
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Obtener modulos'
            ];
        }
    }

    public static function obtenerCodigosPorRubro($rubros = [], $db): object
    {
        $strRubros = count($rubros) > 0 ? implode(',', array_map(function ($e) {
            return "'" . mb_strtoupper($e, 'utf-8') . "'";
        }, $rubros)) : '0';
        $query = "SELECT distinct(empresas.codempresa) codempresa
        FROM sistema.datos_empresas empresas
        INNER join sistema.config_rubrosEmpresa config on empresas.id = config.idEmpresa and config.estado = 1
        inner join general.cat_rubrosEmpresa rubros on config.idRubro = rubros.id and rubros.estado = 1
        WHERE empresas.estado = 1 and rubros.rubro in (" . $strRubros . ");";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);

        try {
            $stmt->execute();
            $data = $stmt->fetchAll(PDO::FETCH_OBJ);

            $codigos = array_column($data, 'codempresa');
            return (object)[
                'status' => 200,
                'data' => $codigos
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage()
            ];
        }
    }

    public static function obtenerPorUsuarioModulo($usuario, $modulo, $db): object
    {
        $query = "SELECT config.id,
            config.idEmpresa,
            config.codempresa,
            config.nombreEmpresa,
            config.idSuperior
        FROM sistema.config_empresasUsuario config WHERE config.estado = 1 AND config.idUsuario = :usuario AND config.idModulo = :modulo;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
        $stmt->bindParam(':modulo', $modulo, PDO::PARAM_INT);

        try {
            $stmt->execute();

            $data = $stmt->fetchAll(PDO::FETCH_OBJ);

            return (object)[
                'status' => 200,
                'data' => $data
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage()
            ];
        }
    }

    public static function obtenerTodasPorUsuarioModulo($usuario, $modulo, $idSuperior, $rubros = []): object
    {
        $solicitud = self::obtenerTodos();

        if ($solicitud->status != 200) {
            return $solicitud;
        }

        $db = obtenerConexion();

        try {
            $solicitudAsignaciones = self::obtenerPorUsuarioModulo($usuario, $modulo, $db);

            if ($solicitudAsignaciones->status != 200) {
                return $solicitudAsignaciones;
            }

            $asignaciones = $solicitudAsignaciones->data;

            $asignaciones = array_values(array_filter($asignaciones, function ($e) use ($idSuperior) {
                return $e->idSuperior == $idSuperior;
            }));

            $empresas = $solicitud->data;

            $empresasAsignadas = array_column($asignaciones, 'codempresa');

            if (in_array('0', $empresasAsignadas)) {
                $empresasAsignadas = array_column($empresas, 'codempresa');
            }

            $empresasRubro = [];

            if (count($rubros) > 0) {
                $solicitudRubros = self::obtenerCodigosPorRubro($rubros, $db);
                if ($solicitudRubros->status != 200) {
                    return $solicitudRubros;
                }

                $empresasRubro = $solicitudRubros->data;
            }

            $empresas = array_values(array_filter($empresas, function ($e) use ($empresasAsignadas) {
                return in_array($e->codempresa, $empresasAsignadas);
            }));

            if (count($rubros) > 0) {
                $empresas = array_values(array_filter($empresas, function ($e) use ($empresasRubro) {
                    return in_array($e->codempresa, $empresasRubro);
                }));
            }

            $empresas = array_values(array_map(function ($e) use ($asignaciones) {
                $idConfiguracion = $asignaciones[array_search($e->codempresa, array_column($asignaciones, 'codempresa'))]->id;

                $tmp = (object)[
                    'codempresa' => $e->codempresa,
                    'nombreEmpresa' => $e->nombreEmpresa,
                    'idConfiguracion' => $idConfiguracion,
                ];

                return $tmp;
            }, $empresas));

            return (object)[
                'status' => 200,
                'data' => $empresas
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage()
            ];
        }
    }

    public static function obtenerPorModulo($idModulo): object
    {
        $db = obtenerConexion();

        $query = "SELECT * FROM sistema.view_empresasModulos WHERE estado = 1 AND idModulo = :modulo;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':modulo', $idModulo, PDO::PARAM_INT);

        try {
            $stmt->execute();
            $data = $stmt->fetchAll(PDO::FETCH_OBJ);
            return (object)[
                'status' => 200,
                'data' => $data
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage()
            ];
        }
    }

    public static function obtenerPorCodempresa(int $codempresa): object
    {
        $request = self::obtenerTodos();

        if ($request->status != 200) {
            return $request;
        }

        $data = $request->data;

        $empresas = array_filter($data, function ($e) use ($codempresa) {
            return $e->codempresa == $codempresa;
        });

        $empresa = (object)[];
        !empty($empresas) && $empresa = array_values($empresas)[0];

        return (object)[
            'status' => 200,
            'data' => $empresa
        ];
    }

    public static function guardarAsignacionUsuarioModulo($idAsignacion, $usuario, $idModulo, $idEmpresa, $codempresa, $empresa, $idSuperior, $db): object
    {
        $respuesta = null;
        $idGuardado = null;

        $idSuperior = empty($idSuperior) ? 0 : $idSuperior;
        $query = "EXEC sistema.sp_guardarEmpresaUsuarioModulo :idAsignacion,:usuario,:idModulo,:idEmpresa,:codempresa,:empresa,:idSuperior,:respuesta,:idGuardado;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':idAsignacion', $idAsignacion, PDO::PARAM_INT);
        $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
        $stmt->bindParam(':idModulo', $idModulo, PDO::PARAM_INT);
        $stmt->bindParam(':idEmpresa', $idEmpresa, PDO::PARAM_INT);
        $stmt->bindParam(':codempresa', $codempresa, PDO::PARAM_INT);
        $stmt->bindParam(':empresa', $empresa, PDO::PARAM_STR);
        $stmt->bindParam(':idSuperior', $idSuperior, PDO::PARAM_INT);
        $stmt->bindParam(':respuesta', $respuesta, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000);
        $stmt->bindParam(':idGuardado', $idGuardado, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 4000);

        try {
            $stmt->execute();
            return (object)[
                'status' => 200,
                'message' => $respuesta,
                'id' => $idGuardado
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Guardado de empresa'
            ];
        }
    }

    public static function limpiarAsignacionesPorUsuarioModulo($usuario, $idModulo, $asignacionesValidas = [], $db): object
    {
        $strAsignaciones = count($asignacionesValidas) > 0 ? implode(',', $asignacionesValidas) : '0';
        $query = "EXEC sistema.sp_limpiarEmpresaUsuarioModulo :usuario,:idModulo,:asignacionesValidas;";
        $stmt = $db->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
        $stmt->bindParam(':usuario', $usuario, PDO::PARAM_INT);
        $stmt->bindParam(':idModulo', $idModulo, PDO::PARAM_INT);
        $stmt->bindParam(':asignacionesValidas', $strAsignaciones, PDO::PARAM_STR);

        try {
            $stmt->execute();
            return (object)[
                'status' => 200,
                'message' => 'Asignaciones limpiadas'
            ];
        } catch (PDOException $e) {
            return (object)[
                'status' => 500,
                'message' => $e->getMessage() . ' Guardado de empresa'
            ];
        }
    }
}
