<?php
    namespace Workbloom\Component\Auth\v0\Models;

    use DateTime;
    use Exception;
    use Workbloom\Services\DB;
    use Workbloom\Component\Auth\v0\DTO\UsuarioDTO;
    use Workbloom\Component\Auth\v0\DTO\UsuarioTokenDTO;
    
    class UsuarioModel {
        protected string $empresaTable = 'empresa';
        protected string $usuarioTable = 'usuario';
        protected string $usuarioTokenTable = 'usuario_token';
        protected string $usuarioEmpresaTable = 'usuario_empresa';

        /**
         * Armazena um novo usuário no banco de dados.
         *
         * Este método insere os dados de um novo usuário na tabela `{$this->usuarioTable}`, incluindo informações de segurança como hash de senha, status e configurações de expiração de senha. A operação é protegida por um bloco `try-catch` para garantir o tratamento de erros.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `INSERT` com todos os campos preenchidos a partir do `UsuarioDTO`.
         * 2.  **Confirmação e Retorno de Sucesso:** Se a inserção for bem-sucedida, retorna um array com **`status` 'success'**, código **201 Created** e os dados do usuário criado (ID e UUID).
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, código **500 Internal Server Error** (ou o código da exceção) e a mensagem detalhada de erro.
         *
         * @param UsuarioDTO $usuarioDTO O objeto DTO contendo os dados do usuário a ser criado.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do usuário criado.
         */
        public function storeUsuario(UsuarioDTO $usuarioDTO): array {
            try {
                $sql =
                "INSERT INTO {$this->usuarioTable} (
                    uuid,
                    status_id,
                    is_root,
                    nome_completo,
                    nome_usuario,
                    email,
                    senha_hash,
                    need_update_password,
                    days_to_expire_password,
                    last_password_update,
                    created_at,
                    updated_at,
                    deleted_at
                ) VALUES (
                    :uuid,
                    :status_id,
                    :is_root,
                    :nome_completo,
                    :nome_usuario,
                    :email,
                    :senha_hash,
                    :need_update_password,
                    :days_to_expire_password,
                    :last_password_update,
                    :created_at,
                    :updated_at,
                    :deleted_at
                )";

                $params = [
                    ":uuid"=> $usuarioDTO->getUuid(),
                    ":status_id"=> $usuarioDTO->getStatusId(),
                    ":is_root"=> $usuarioDTO->getIsRoot(),
                    ":nome_completo"=> $usuarioDTO->getNomeCompleto(),
                    ":nome_usuario"=> $usuarioDTO->getNomeUsuario(),
                    ":email"=> $usuarioDTO->getEmail(),
                    ":senha_hash"=> $usuarioDTO->getSenhaHash(),
                    ":need_update_password"=> $usuarioDTO->getNeedUpdatePassword(),
                    ":days_to_expire_password"=> $usuarioDTO->getDaysToExpirePassword(),
                    ":last_password_update"=> $usuarioDTO->getLastPasswordUpdate(),
                    ":created_at"=> $usuarioDTO->getCreatedAt(),
                    ":updated_at"=> $usuarioDTO->getUpdatedAt(),
                    ":deleted_at"=> $usuarioDTO->getDeletedAt(),
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 201,
                    'status' => 'success',
                    'message' => 'Usuário criado com sucesso',
                    'output' => [
                        'data' => [
                            'id' => DB::lastInsertId(),
                            'uuid' => $usuarioDTO->getUuid()
                        ]
                    ]
                ];
            } catch (Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Atualiza um usuário existente no banco de dados.
         *
         * Este método modifica os dados de um usuário na tabela `{$this->usuarioTable}` com base no **UUID** fornecido no objeto `UsuarioDTO`. Ele atualiza informações de segurança e perfil, como hash de senha, status, permissão de root, nome e configurações de expiração de senha. A operação utiliza um bloco `try-catch` para garantir o tratamento de erros.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `UPDATE` com todos os campos preenchidos a partir do `UsuarioDTO`, modificando o registro correspondente ao UUID.
         * 2.  **Confirmação e Retorno de Sucesso:** Se a atualização for bem-sucedida, retorna um array com **`status` 'success'**, código **200 OK** e uma mensagem de êxito.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e a mensagem detalhada de erro.
         *
         * @param UsuarioDTO $usuarioDTO O objeto DTO contendo os dados atualizados do usuário, incluindo o UUID para identificação.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e uma mensagem.
         */
        public function updateUsuario(UsuarioDTO $usuarioDTO): array {
            try {
                $sql = 
                "UPDATE {$this->usuarioTable} SET
                    status_id = :status_id,
                    is_root = :is_root,
                    nome_completo = :nome_completo,
                    nome_usuario = :nome_usuario,
                    email = :email,
                    senha_hash = :senha_hash,
                    need_update_password = :need_update_password,
                    days_to_expire_password = :days_to_expire_password,
                    last_password_update = :last_password_update,
                    updated_at = :updated_at
                WHERE uuid = :uuid";

                $params = [
                    ":status_id" => $usuarioDTO->getStatusId(),
                    ":is_root" => $usuarioDTO->getIsRoot(),
                    ":nome_completo" => $usuarioDTO->getNomeCompleto(),
                    ":nome_usuario" => $usuarioDTO->getNomeUsuario(),
                    ":email" => $usuarioDTO->getEmail(),
                    ":senha_hash" => $usuarioDTO->getSenhaHash(),
                    ":need_update_password" => $usuarioDTO->getNeedUpdatePassword(),
                    ":days_to_expire_password" => $usuarioDTO->getDaysToExpirePassword(),
                    ":last_password_update" => $usuarioDTO->getLastPasswordUpdate(),
                    ":updated_at" => $usuarioDTO->getUpdatedAt(),
                    ":uuid" => $usuarioDTO->getUuid(),
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Usuário atualizado com sucesso',
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Realiza a exclusão lógica de um usuário no banco de dados.
         *
         * Este método atualiza a coluna `deleted_at` do registro do usuário na tabela `{$this->usuarioTable}` com o timestamp fornecido no objeto `UsuarioDTO`. Isso garante uma **exclusão lógica**, mantendo o registro para fins de auditoria, mas marcando-o como inativo.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `UPDATE` que define a data de exclusão para o registro correspondente ao UUID do usuário.
         * 2.  **Retorno de Sucesso:** Se a atualização for bem-sucedida, retorna um array com **`status` 'success'**, código **200 OK** e uma mensagem de êxito.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e a mensagem detalhada da exceção.
         *
         * @param UsuarioDTO $usuarioDTO O objeto DTO contendo o UUID do usuário a ser excluído e o timestamp a ser definido em `deleted_at`.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e uma mensagem.
         */
        public function deleteUsuario(UsuarioDTO $usuarioDTO): array {
            try {
                $sql = 
                "UPDATE {$this->usuarioTable} SET
                    deleted_at = :deleted_at
                WHERE uuid = :uuid";

                $params = [
                    ":deleted_at" => $usuarioDTO->getDeletedAt(),
                    ":uuid" => $usuarioDTO->getUuid(),
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Usuário excluído com sucesso',
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca um único usuário no banco de dados por um identificador específico.
         *
         * Este método recupera todos os detalhes de um usuário da tabela `{$this->usuarioTable}`. A busca é flexível e permite usar qualquer coluna como identificador (`$identifier`) e o valor correspondente.
         *
         * #### Fluxo de Operação:
         * 1.  **Construção da Query Dinâmica:** O método monta e executa uma consulta `SELECT` que usa o `$identifier` de forma dinâmica na cláusula `WHERE` e um parâmetro nomeado seguro (`:value`) para o valor.
         * 2.  **Execução da Consulta:** A consulta usa `DB::fetchOne`, indicando que apenas um registro é esperado.
         * 3.  **Verificação de Resultados:**
         * * Se o usuário for encontrado, retorna um array com **`status` 'success'**, código **200 OK** e os dados do usuário na chave `output`.
         * * Se o usuário **não for encontrado** (`empty($result)`), retorna um array com **`status` 'error'** e código **404 Not Found**, com uma mensagem indicando que o usuário não foi encontrado.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $identifier A coluna da tabela a ser usada como critério de busca (ex: 'uuid', 'email', 'nome_usuario').
         * @param mixed $value O valor correspondente ao identificador que está sendo buscado.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do usuário, se encontrado.
         */
        public function findUsuarioByIdentifier(string $identifier, mixed $value): array {
            try {
                $sql = 
                "SELECT
                    id,
                    uuid,
                    status_id,
                    is_root,
                    nome_completo,
                    nome_usuario,
                    email,
                    senha_hash,
                    need_update_password,
                    days_to_expire_password,
                    last_password_update,
                    created_at,
                    updated_at,
                    deleted_at
                FROM {$this->usuarioTable}
                WHERE {$identifier} = :value";

                $params = [
                    ":value" => $value,
                ];

                $result = DB::fetchOne(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Usuário não encontrado',
                    ];
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Usuário encontrado com sucesso',
                    'output' => [
                        'data' => $result
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca um único usuário no banco de dados usando seu e-mail ou nome de usuário como critério de login.
         *
         * Este método é utilizado para o processo de autenticação, tentando encontrar um usuário na tabela `{$this->usuarioTable}` por meio de uma correspondência na coluna `nome_usuario` ou `email`.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Monta e executa uma consulta `SELECT` que usa o valor `$login` para tentar encontrar um registro no campo `email` ou `nome_usuario`.
         * 2.  **Verificação de Resultados:**
         * * Se o usuário for encontrado, retorna um array com **`status` 'success'**, código **200 OK** e os dados do usuário na chave `output`.
         * * Se o usuário **não for encontrado** (`empty($result)`), retorna um array com **`status` 'error'** e código **404 Not Found**, com uma mensagem indicando que o usuário não foi encontrado.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $login O valor do e-mail ou nome de usuário a ser pesquisado.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do usuário, se encontrado.
         */
        public function findUsuarioByLogin(string $login): array {
            try {
                $sql = 
                "SELECT
                    id,
                    uuid,
                    status_id,
                    is_root,
                    nome_completo,
                    nome_usuario,
                    email,
                    senha_hash,
                    need_update_password,
                    days_to_expire_password,
                    last_password_update,
                    created_at,
                    updated_at,
                    deleted_at
                FROM {$this->usuarioTable}
                WHERE (nome_usuario = :value OR email = :value)";

                $params = [
                    ":value" => $login,
                ];

                $result = DB::fetchOne(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Usuário não encontrado',
                    ];
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Usuário encontrado com sucesso',
                    'output' => [
                        'data' => $result
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Armazena um novo token de autenticação de usuário no banco de dados.
         *
         * Este método é responsável por registrar o token na tabela `{$this->usuarioTokenTable}`, associando-o ao usuário, IP, User Agent e definindo seu status de revogação e tempo de expiração.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `INSERT` para inserir o registro do token com todos os detalhes fornecidos pelo `UsuarioTokenDTO`.
         * 2.  **Confirmação e Retorno de Sucesso:** Se a inserção for bem-sucedida, retorna um array com **`status` 'success'**, código **201 Created** e os dados do token (ID gerado e o token).
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e a mensagem detalhada de erro.
         *
         * @param UsuarioTokenDTO $usuarioTokenDTO O objeto DTO contendo os dados do token a ser armazenado.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do token.
         */
        public function storeUsuarioToken(UsuarioTokenDTO $usuarioTokenDTO): array {
            try {
                $sql =
                "INSERT INTO {$this->usuarioTokenTable} (
                    usuario_id,
                    usuario_ip,
                    usuario_user_agent,
                    token,
                    is_revoked,
                    created_at,
                    expires_at
                ) VALUES (
                    :usuario_id,
                    :usuario_ip,
                    :usuario_user_agent,
                    :token,
                    :is_revoked,
                    :created_at,
                    :expires_at
                )";

                $params = [
                    ":usuario_id"=> $usuarioTokenDTO->getUsuarioId(),
                    ":usuario_ip"=> $usuarioTokenDTO->getUsuarioIp(),
                    ":usuario_user_agent"=> $usuarioTokenDTO->getUsuarioUserAgent(),
                    ":token"=> $usuarioTokenDTO->getToken(),
                    ":is_revoked"=> $usuarioTokenDTO->getIsRevoked(),
                    ":created_at"=> $usuarioTokenDTO->getCreatedAt(),
                    ":expires_at"=> $usuarioTokenDTO->getExpiresAt(),
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 201,
                    'status' => 'success',
                    'message' => 'Token de usuário criado com sucesso',
                    'output' => [
                        'data' => [
                            'id' => DB::lastInsertId(),
                            'token' => $usuarioTokenDTO->getToken()
                        ]
                    ]
                ];
            } catch (Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Atualiza o status de revogação de um token de usuário no banco de dados.
         *
         * Este método modifica o registro de um token na tabela `{$this->usuarioTokenTable}`, alterando o status de revogação (`is_revoked`) e o timestamp de revogação (`revoked_at`), com base na string do token fornecida no DTO.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `UPDATE` para modificar o status de revogação do token.
         * 2.  **Retorno de Sucesso:** Se a atualização for bem-sucedida, retorna um array com **`status` 'success'**, código **200 OK** e uma mensagem de êxito.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e a mensagem detalhada de erro.
         *
         * @param UsuarioTokenDTO $usuarioTokenDTO O objeto DTO contendo o token a ser atualizado, o novo status de revogação (`is_revoked`) e a data de revogação (`revoked_at`).
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e uma mensagem.
         */
        public function updateUsuarioToken(UsuarioTokenDTO $usuarioTokenDTO): array {
            try {
                $sql =
                "UPDATE {$this->usuarioTokenTable} SET
                    is_revoked = :is_revoked,
                    revoked_at = :revoked_at
                WHERE token = :token";

                $params = [
                    ":is_revoked"=> $usuarioTokenDTO->getIsRevoked(),
                    ":revoked_at"=> $usuarioTokenDTO->getRevokedAt(),
                    ":token"=> $usuarioTokenDTO->getToken(),
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Token de usuário atualizado com sucesso',
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Revoga (invalida) todos os tokens de autenticação ativos de um usuário no banco de dados, buscando o usuário pelo UUID.
         *
         * Este método executa uma exclusão lógica em todos os tokens não revogados (`is_revoked = 0`) associados ao ID interno de um usuário, que é determinado pelo `usuario_uuid` fornecido.
         *
         * #### Atenção à Sintaxe SQL (PostgreSQL/SQL Server):
         * A sintaxe `UPDATE ... FROM` é comum em PostgreSQL ou SQL Server e está sendo usada para realizar um JOIN implícito na instrução UPDATE, o que não é sintaxe padrão do MySQL. Assumindo que o ambiente de banco de dados suporte essa sintaxe (ou que o código seja adaptado para o SGBD correto).
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Prepara e executa a instrução `UPDATE` para definir `is_revoked = 1` e `revoked_at` para o timestamp atual para todos os tokens ativos do usuário.
         * 2.  **Confirmação e Retorno de Sucesso:** Se a atualização for bem-sucedida, retorna um array com **`status` 'success'**, código **200 OK** e uma mensagem de êxito.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $usuario_uuid O UUID do usuário para o qual os tokens serão revogados.
         * @return array Um array associativo contendo o status da operação ("success" ou "error"), um código de resposta HTTP e uma mensagem.
         */
        public function revokeOldUsuarioTokens(string $usuario_uuid): array {
            try {
                $sql =
                "UPDATE {$this->usuarioTokenTable} AS ut SET
                    is_revoked = 1,
                    revoked_at = :revoked_at
                FROM {$this->usuarioTable} AS u
                WHERE ut.usuario_id = u.id
                AND u.uuid = :usuario_uuid
                AND ut.is_revoked = 0";

                $params = [
                    ":revoked_at"=> (new DateTime())->format(format: 'Y-m-d H:i:s'),
                    ":usuario_uuid"=> $usuario_uuid
                ];

                // Executa a query
                DB::execute(sql: $sql, params: $params);

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Tokens antigos revogados com sucesso',
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca um registro de token de usuário no banco de dados por um identificador específico.
         *
         * Este método recupera todos os detalhes de um token de autenticação (JWT) da tabela `{$this->usuarioTokenTable}` de forma flexível, permitindo a busca por qualquer coluna (`$identifier`) e o valor correspondente.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Monta e executa uma consulta `SELECT` que usa o `$identifier` de forma dinâmica na cláusula `WHERE` e um parâmetro nomeado seguro (`:value`) para o valor. A consulta utiliza `DB::fetchOne`, indicando que apenas um registro é esperado.
         * 2.  **Verificação de Resultados:**
         * - Se o token **não for encontrado** (`empty($result)`), retorna um array com **`status` 'error'** e código **404 Not Found**.
         * - Se o token for encontrado, retorna um array com **`status` 'success'**, código **200 OK** e os dados do registro na chave `output`.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $identifier A coluna da tabela a ser usada como critério de busca (ex: 'token', 'usuario_id', 'ip_address').
         * @param mixed $value O valor correspondente ao identificador que está sendo buscado.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do token, se encontrado.
         */
        public function findUsuarioTokenByIdentifier(string $identifier, mixed $value): array {
            try {
                $sql = 
                "SELECT
                    id,
                    usuario_id,
                    usuario_ip,
                    usuario_user_agent,
                    token,
                    is_revoked,
                    created_at,
                    expires_at,
                    revoked_at
                FROM {$this->usuarioTokenTable}
                WHERE {$identifier} = :value";

                $params = [
                    ":value" => $value,
                ];

                $result = DB::fetchOne(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Token de usuário não encontrado',
                    ];
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Token de usuário encontrado com sucesso',
                    'output' => [
                        'data' => $result
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca e retorna todos os contextos de trabalho (empresas) associados a um usuário, identificando o usuário pelo seu UUID.
         *
         * Este método consulta a tabela de associação usuário-empresa para listar todas as empresas ativas (`status_id = 1`) às quais um usuário específico tem acesso.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Executa uma consulta `SELECT` que une as tabelas de usuário, empresa e a tabela de associação (`{$this->usuarioEmpresaTable}`) para filtrar pelo `usuario_uuid`. A busca retorna múltiplos registros (empresas).
         * 2.  **Verificação de Resultados:**
         * - Se **nenhum contexto de trabalho for encontrado** (`empty($result)`), retorna um array com **`status` 'error'** e código **404 Not Found**.
         * - Se contextos forem encontrados, retorna um array com **`status` 'success'**, código **200 OK** e os dados das empresas encontradas na chave `output`.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $usuario_uuid O UUID do usuário para o qual os contextos de trabalho serão buscados.
         * @return array Um array associativo contendo o status da operação, o código de resposta HTTP e os dados dos contextos de trabalho, se encontrados.
         */
        public function findWorkContextsByUsuarioUUID(string $usuario_uuid): array {
            try {
                $sql =
                "SELECT
                    'Empresa' AS contexto_tipo,
                    e.uuid AS contexto_uuid,
                    e.razao_social,
                    e.nome_fantasia,
                    e.document_inscricao
                FROM {$this->usuarioEmpresaTable} ue
                LEFT JOIN {$this->usuarioTable} u ON ue.usuario_id = u.id
                LEFT JOIN {$this->empresaTable} e ON ue.empresa_id = e.id
                WHERE u.uuid = :usuario_uuid
                AND e.status_id = :status_id";

                $params = [
                    ":usuario_uuid"=> $usuario_uuid,
                    ":status_id" => 1
                ];

                // Executa a query
                $result = DB::fetchAll(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Contextos de trabalho não encontrados para o usuário',
                    ];
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Contextos de trabalho encontrados com sucesso',
                    'output' => [
                        'data' => ['contextos' => $result]
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca e retorna todos os contextos de trabalho (empresas) ativos no sistema.
         *
         * Este método consulta a tabela `{$this->empresaTable}` para listar todas as empresas que estão marcadas como ativas (`status_id = 1`). É útil para a administração do sistema que precisa listar todas as entidades disponíveis.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Executa uma consulta `SELECT` para buscar as informações essenciais de todas as empresas com `status_id = 1`.
         * 2.  **Verificação de Resultados:**
         * * Se **nenhum contexto de trabalho for encontrado** (`empty($result)`), retorna um array com **`status` 'error'** e código **404 Not Found**, com uma mensagem indicando a ausência de contextos.
         * * Se contextos forem encontrados, retorna um array com **`status` 'success'**, código **200 OK** e os dados das empresas na chave `output`.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados dos contextos de trabalho, se encontrados.
         */
        public function findAllWorkContexts(int $is_root = 0): array {
            try {
                $sql =
                "SELECT
                    'Empresa' AS contexto_tipo,
                    e.uuid AS contexto_uuid,
                    e.razao_social,
                    e.nome_fantasia,
                    e.document_inscricao
                FROM {$this->empresaTable} e
                WHERE e.status_id = :status_id";

                $params = [
                    ":status_id" => 1
                ];

                // Executa a query
                $result = DB::fetchAll(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Contextos de trabalho não encontrados para o usuário',
                    ];
                }

                // Adiciona o contexto da plataforma se o usuário for Administrador
                if($is_root === 1) {
                    $adminContext = [
                        'contexto_tipo' => 'Sistema',
                        'contexto_uuid' => '019a07ee-0c7c-7dd7-a447-802ede64dc98',
                        'nome' => 'Área do Administrador'
                    ];

                    $result = array_merge([$adminContext], $result);
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Contextos de trabalho encontrados com sucesso',
                    'output' => [
                        'data' => ['contextos' => $result]
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }

        /**
         * Busca um contexto de trabalho (empresa) específico e verifica se o usuário tem permissão para acessá-lo.
         *
         * Este método é crucial para a validação do contexto de trabalho de um usuário (por exemplo, ao iniciar uma sessão em uma empresa). Ele usa uma lógica de consulta SQL para determinar se o `usuario_uuid` está associado à `contexto_uuid` fornecida ou se o usuário é um administrador de sistema (root).
         *
         * #### Fluxo de Permissão Lógica:
         * A cláusula `WHERE` verifica DUAS condições de permissão:
         * 1.  **Associação Direta/Normal (EXISTS):** O usuário está diretamente associado à empresa (`ue.usuario_id = u.id AND ue.empresa_id = e.id`).
         * 2.  **Permissão de Root (OR EXISTS):** O usuário possui a flag `is_root = 1`.
         *
         * #### Fluxo de Operação:
         * 1.  **Execução da Query:** Executa uma consulta `SELECT` complexa que filtra as empresas por `contexto_uuid` e `status_id = 1`, além de verificar a permissão do usuário via `EXISTS`.
         * 2.  **Verificação de Resultados:**
         * * Se o contexto for encontrado e o usuário tiver permissão, retorna um array com **`status` 'success'** e código **200 OK**, com os dados do contexto.
         * * Se o contexto **não for encontrado** ou o usuário **não tiver permissão** (o que resulta em `empty($result)` devido ao `WHERE`), retorna um array com **`status` 'error'** e código **404 Not Found**.
         *
         * #### Tratamento de Erros:
         * - Qualquer `Exception` capturada durante o processo retorna um array com **`status` 'error'**, o código de erro da exceção (ou `500` como fallback) e uma mensagem detalhada de erro.
         *
         * @param string $usuario_uuid O UUID do usuário cuja permissão de acesso está sendo verificada.
         * @param string $contexto_uuid O UUID da empresa/contexto de trabalho que o usuário está tentando acessar.
         * @return array Um array associativo contendo o status da operação, um código de resposta HTTP e os dados do contexto, se encontrado.
         */
        public function findWorkContextByUsuarioAndContextoUUID(string $usuario_uuid, string $contexto_uuid): array {
            try {
                $sql = 
                "SELECT
                    'Empresa' AS contexto_tipo,
                    e.uuid AS contexto_uuid,
                    e.razao_social,
                    e.nome_fantasia,
                    e.document_inscricao
                FROM {$this->empresaTable} e
                WHERE 
                    (
                        EXISTS (
                            SELECT 1
                            FROM {$this->usuarioEmpresaTable} ue
                            INNER JOIN {$this->usuarioTable} u 
                                ON ue.usuario_id = u.id
                            WHERE 
                                ue.empresa_id = e.id
                                AND u.uuid = :usuario_uuid
                        )
                        OR EXISTS (
                            SELECT 1
                            FROM {$this->usuarioTable} u2
                            WHERE 
                                u2.uuid = :usuario_uuid
                                AND u2.is_root = 1
                        )
                    )
                AND e.uuid = :contexto_uuid
                AND e.status_id = :status_id";

                $params = [
                    ":usuario_uuid"=> $usuario_uuid,
                    ":contexto_uuid"=> $contexto_uuid,
                    ":status_id" => 1
                ];

                // Executa a query
                $result = DB::fetchOne(sql: $sql, params: $params);
                if(empty($result)) {
                    return [
                        'response_code' => 404,
                        'status' => 'error',
                        'message' => 'Contexto de trabalho não encontrado para o usuário',
                    ];
                }

                return [
                    'response_code' => 200,
                    'status' => 'success',
                    'message' => 'Contexto de trabalho encontrado com sucesso',
                    'output' => [
                        'data' => $result
                    ]
                ];
            } catch(Exception $e) {
                return [
                    'response_code' => $e->getCode() ?? 500,
                    'status' => 'error',
                    'message' => $e->getMessage() ?? 'Internal Server Error'
                ];
            }
        }
    }