<?php

class Sistema_Model_Usuarios extends Agro_Db_Table_Abstract
{
	protected $_rowClass = 'Sistema_Model_Row_Usuario';
	protected $_sequence = 'sistema.usuarios_id_seq';
	protected $_schema = 'sistema';
	protected $_name = 'usuarios';
	protected $_primary = 'id';

    const TIPO_USUARIO_ASSESSORIA = 'A';
    const TIPO_USUARIO_CORRETOR = 'C';
    const TIPO_USUARIO_FUNCIONARIO = 'F';
    const TIPO_USUARIO_HELPER = 'H';
    const TIPO_USUARIO_MANAGER = 'M';
    const TIPO_USUARIO_PREPOSTO = 'P';
    const TIPO_USUARIO_TEMPORARIO = 'T';
    const TIPO_USUARIO_VISTORIADOR = 'V';

    const PERFIL_ADMIN = 12;
	const PERFIL_SEGURADORA = 21;
	const PERFIL_RESSEGURADORA = 22;
	const PERFIL_SEGURADORA_SCOR = 29;
    const PERFIL_VISTORIADOR = 18;
	const PERFIL_VISTORIADOR_RESPONSAVEL = 30;
	const PERFIL_SEGURADORA_ESSOR = 31;
	const PERFIL_RESSEGURADOR_SINISTRO = 32;
	
	public function fetchAuth($id) {
		$select = $this->select()->setIntegrityCheck(false);
		$select->from(array('u' => 'sistema.usuarios'));
		$select->join(array('r' => 'sistema.roles'), 'u.id_role = r.id', array('ds_chave'));
		$select->where('u.id = ?', $id);

		return $this->fetchRow($select);
	}

	public function save(array $data)
    {
        try {
            $validarSenha = !empty($data['validarSenha']);

            if ($validarSenha) {
                $agroSenha = new Agro_Senha();
                $agroSenha->verificarHistoricoSenhas(true, (int)$data['id_usuario']);
                $senhaValida = $agroSenha->validarSenha($data['ds_senha'], $data['ds_senha2']);

                if (!$senhaValida) {
                    $this->setMessage($agroSenha->retornarMensagemErros());
                    return false;
                }
            }

            $row = $this->getRow($data['id_usuario']);

            if (isset($data['fl_ativo'])) {
                $row->fl_ativo = $data['fl_ativo'] ? 't' : 'f';
            }

			if ($data['id_usuario']) {
				$hash = password_hash(trim($data['ds_senha']), PASSWORD_BCRYPT);
                $dataExpiracaoSenha = new DateTime('now');
                $dataExpiracaoSenha->add(new DateInterval('P4M'));

                if ($validarSenha && $row->ds_senha !== $hash) {
                    $row->dt_expiracao_senha = $dataExpiracaoSenha->format('Y-m-d H:i:s');
                    $row->fl_notificado_expiracao_senha = 0;
                    $row->fl_notificado_bloqueio_inatividade = 0;
                    $row->fl_bloqueio_inatividade = 0;
                }

				$row->id_role = !empty($data['id_role'])
                    ? $data['id_role']
                    : (!empty($row->id_role) ? $row->id_role : null);
				$row->ds_nome_usuario = trim($data['ds_nome_usuario']);
				$row->ds_senha = ($data['ds_senha'] ? $hash : $row->ds_senha);
				$row->tp_usuario = !empty($data['tp_usuario'])
                    ? $data['tp_usuario']
                    : (!empty($row->tp_usuario) ? $row->tp_usuario : null);
				$row->ds_url_senha = $data['ds_url_senha'] ?? $row->ds_url_senha;

				if (isset($data['fl_liberado_tablet_previa'])) {
					$row->fl_liberado_tablet_previa = ($data['fl_liberado_tablet_previa'] ? 1 : 0);
				}
				if (isset($data['fl_liberado_tablet_sinistro'])) {
					$row->fl_liberado_tablet_sinistro = ($data['fl_liberado_tablet_sinistro'] ? 1 : 0);
				}

                $save = $row->save();

                if ($validarSenha && $save) {
                    (new Sistema_Model_UsuarioHistoricoSenha())->save((int) $row->id, $hash);
                }

				return $save;
			} else {
                if (!$data['ds_senha']) {
                    $this->setMessage('É Necessário informar uma senha para este usuário.');
                    return false;
                }

                $hash = password_hash(trim($data['ds_senha']), PASSWORD_BCRYPT);

                $row->id = ($data['id_usuario'] ?? $this->getNextSequence());
                $row->id_role = $data['id_role'];
                $row->ds_nome_usuario = trim($data['ds_nome_usuario']);
                $row->ds_senha = $hash;
                $row->tp_usuario = $data['tp_usuario'];
                $row->ds_url_senha = $data['ds_url_senha'] ?? '';

                $dataExpiracaoSenha = new DateTime('now');
                $dataExpiracaoSenha->add(new DateInterval('P4M'));

                $row->dt_expiracao_senha = $dataExpiracaoSenha->format('Y-m-d H:i:s');

                if (isset($data['fl_liberado_tablet_previa'])) {
                    $row->fl_liberado_tablet_previa = ($data['fl_liberado_tablet_previa'] ? 1 : 0);
                }
                if (isset($data['fl_liberado_tablet_sinistro'])) {
                    $row->fl_liberado_tablet_sinistro = ($data['fl_liberado_tablet_sinistro'] ? 1 : 0);
                }

                return $row->save();
			}

		} catch (Exception $e) {
			$this->setMessage($e);
			if ($e->getCode() == '23505') {
				$this->setMessage('Já existe um usuário com este nome, informe outro nome de usuário.');
			}
			return false;
		}
	}

    public function getComplete($usuario) {
        return $this->fetchAll(
            $this->select()->setIntegrityCheck(false)
            ->from(['u' => 'sistema.usuarios'], 'ds_nome_usuario')
            ->where('ds_nome_usuario ilike ?', "$usuario%")
            ->where('fl_ativo = true')
        );
    }

	public function getUsuario($usuario) {
		$select = $this->select()->setIntegrityCheck(false);
		$select->from(array('u' => 'sistema.usuarios'), '*');
		$select->joinLeft(array('f' => 'sistema.funcionarios'), 'u.id = f.id_usuario', array('ds_email as email_funcionario', 'ds_nome_funcionario'));
		$select->joinLeft(array('c' => 'sistema.corretores'), 'u.id = c.id_usuario', array('ds_email as email_corretor', 'ds_nome_fantasia'));
		$select->joinLeft(array('p' => 'sistema.prepostos'), 'u.id = p.id_usuario', array('ds_email as email_preposto', 'ds_nome_preposto'));
		$select->joinLeft(array('a' => 'sistema.assessorias'), 'u.id = a.id_usuario', array('ds_email as email_assessoria', 'ds_nome_assessoria'));
		$select->where('ds_nome_usuario = ?', $usuario);
		$Row = $this->fetchRow($select);

		switch ($Row->tp_usuario) {
            case 'V':
            case 'M':
			case 'F':
				return array('nome' => $Row->ds_nome_funcionario, 'user' => $Row->ds_nome_usuario, 'email'=>$Row->email_funcionario, 'pass'=>$Row->ds_senha);
			case 'C':
				return array('nome' => $Row->ds_nome_fantasia, 'user' => $Row->ds_nome_usuario, 'email'=>$Row->email_corretor, 'pass'=>$Row->ds_senha);
			case 'P':
				return array('nome' => $Row->ds_nome_preposto, 'user' => $Row->ds_nome_usuario, 'email'=>$Row->email_preposto, 'pass'=>$Row->ds_senha);
            case 'A':
                return array('nome' => $Row->ds_nome_assessoria, 'user' => $Row->ds_nome_usuario, 'email'=>$Row->email_assessoria, 'pass'=>$Row->ds_senha);
			default:
				return;
		}
	}

	public function beforeDelete($id) {

		$modelUsuarioAcao = new Sistema_Model_UsuarioAcao();
		$modelUsuarioAcao->delete($id, 'id_usuario');
	}

	public function getUser($idUsuario=false, $somenteAtivos = false) {
		$Select = $this->select()->setIntegrityCheck(false);
		$Select->from(array('u' => 'sistema.usuarios'));
		$Select->join(array('r' => 'sistema.roles'), 'u.id_role = r.id', 'ds_chave');

		if ($somenteAtivos === true) {
		    $Select->where('u.fl_ativo is true');
        }

		if ($idUsuario) {
			$Select->where('u.id = ?', $idUsuario);
			return $this->fetchRow($Select);
		} else {
			return $this->fetchAll($Select);
		}
	}

	public function getUsuarioById($idUsuario) {
		$select = $this->select()->setIntegrityCheck(false);
		$select->from(array('u' => 'sistema.usuarios'), '*');
		$select->joinLeft(array('f' => 'sistema.funcionarios'), 'u.id = f.id_usuario');
		$select->joinLeft(array('c' => 'sistema.corretores'), 'u.id = c.id_usuario');
		$select->joinLeft(array('p' => 'sistema.prepostos'), 'u.id = p.id_usuario');
		$select->where('u.id = ?', $idUsuario);
		$Row = $this->fetchRow($select);

		return $Row->ds_nome_usuario;
	}

	public function getNameById($id){
		$Row = $this->getRow($id);
		return $Row->ds_nome_usuario;
	}

	public function isFuncionarioAgro($id_usuario = null)
    {
        return Zend_Auth::getInstance()->getIdentity()->id_empresa === Sistema_Model_Empresas::AGROBRASIL;
	}

	public function getUsuariosByEmpresaMobile($id_empresa) {
		$Select = $this->select()->setIntegrityCheck(false);
		$Select->from(array('u' => 'sistema.usuarios'), array('id','ds_nome_usuario','ds_senha'));
		$Select->join(array('f' => 'sistema.funcionarios'), 'f.id_usuario = u.id', array('ds_nome_funcionario','id_empresa'));
		$Select->where('f.id_empresa = ?', $id_empresa);
		$Select->where('f.fl_ativo = true');
		$Select->order('u.ds_nome_usuario');

		return $this->getAdapter()->fetchAll($Select);
	}

	public function atualizarDispositivoPrevia(int $idUsuario, string $dispositivo = '')
    {
        $row = $this->getRow($idUsuario);
        $row->deviceid = $dispositivo;

        return $row->save();
    }

	public function atualizarDispositivoSinistro(int $idUsuario, string $dispositivo = '')
    {
        $row = $this->getRow($idUsuario);
        $row->deviceid_sinistro = $dispositivo;

        return $row->save();
    }

    public function isUsuarioAgroTi(string $usuario)
    {
        $select = $this->select()->setIntegrityCheck(false);
        $select->from(['u' => "{$this->_schema}.{$this->_name}"], ['id']);
        $select->join(['f' => 'sistema.funcionarios'], 'f.id_usuario = u.id', false);
        $select->join(['d' => 'sistema.departamentos'], 'f.id_departamento = d.id', false);
        $select->join(['e' => 'sistema.empresas'], 'f.id_empresa = e.id', false);
        $select->where('u.ds_nome_usuario = ?', $usuario);
        $select->where("e.cpf_cnpj = '03.486.745/0001-09'");
        $select->where("d.ds_chave = 'TI'");

        return !empty($this->fetchRow($select));
    }

    public function getUsuarioByNomeUsuario(string $nomeUsuario)
    {
        $select = $this->select()->setIntegrityCheck(false);
        $select->from(['u' => "{$this->_schema}.{$this->_name}"], '*');
        $select->where('ds_nome_usuario = ?', $nomeUsuario);

        return $this->fetchRow($select);
    }

    public static function usuarioLogadoFuncionarioAgro()
    {
        return Zend_Auth::getInstance()->getIdentity()->id_empresa === Sistema_Model_Empresas::AGROBRASIL;
    }
    
    /**
     * Retorna se o usuário logado é um funcionário da Agro do departamento da TI
     *
     * @return bool
     */
    public static function usuarioLogadoFuncionarioAgroTI(): bool
    {
        $usuario = Zend_Auth::getInstance()->getIdentity();  
        return $usuario->id_empresa === Sistema_Model_Empresas::AGROBRASIL && $usuario->id_departamento == Sistema_Model_Departamentos::AGRO_TI;
    }

    /**
     * @param int $idUsuario
     * @param string $nomeUsuario
     * @return void
     * @throws Exception
     */
    public static function validarUsuarioExistente(int $idUsuario, string $nomeUsuario)
    {
        $rowUsuario = (new Sistema_Model_Usuarios())->getUsuarioByNomeUsuario($nomeUsuario);

        if (
            !empty($rowUsuario)
            && $rowUsuario['ds_nome_usuario'] === $nomeUsuario
            && $rowUsuario['id'] !== $idUsuario
        ) {
            throw new \Exception("Já existe um usuário {$nomeUsuario}.", 403);
        }
    }

    /**
     * @param string $nomeUsuario
     * @return void
     * @throws Exception
     */
    public static function validarPadraoUsuario(string $nomeUsuario)
    {
        $mensagemErro = "Usuário {$nomeUsuario} inválido. Campo usuário deve seguir preferencialmente o padrão 'nome.sobrenome'";
        $mensagemErro .= ", podendo também ser utilizados números.";
        $totalRegistros = substr_count($nomeUsuario, '.');

        if ($totalRegistros === 0 || $totalRegistros > 1) {
            throw new \Exception($mensagemErro, 403);
        }

        if (preg_match_all("/[^a-zA-Z0-9\.]/", $nomeUsuario, $retorno)) {
            throw new \Exception($mensagemErro, 403);
        }
    }

	public function getComboByIdDepartamento(int $idDepartamento): array
	{
		$rs = $this->getDefaultAdapter()->fetchPairs(
			$this
				->select()
				->setIntegrityCheck(false)
				->from(array('u' => 'sistema.usuarios'), 'id, ds_nome_usuario')
				->join(array('f' => 'sistema.funcionarios'), 'f.id_usuario = u.id', false)
				->where('u.fl_ativo is true')
				->where('f.id_departamento = ?', $idDepartamento)
				->order('ds_nome_usuario')
		);

		$rs[0] = '';

		asort($rs);

		return $rs;
	}
	
	public function tempoSenhaUsuarioPrestesExpirar(int $id): ?Zend_Db_Table_Row_Abstract
	{
        $caseNome = "CASE ";
        $caseNome .= "  WHEN f.id is not null ";
        $caseNome .= "    THEN f.ds_nome_funcionario ";
        $caseNome .= "  WHEN c.id is not null ";
        $caseNome .= "    THEN c.ds_nome_corretor ";
        $caseNome .= "  WHEN p.id is not null ";
        $caseNome .= "    THEN p.ds_nome_preposto ";
        $caseNome .= "  WHEN a.id is not null ";
        $caseNome .= "    THEN a.ds_nome_assessoria ";
        $caseNome .= " END AS nome ";
        $campos = [
            'u.id',
            'u.ds_nome_usuario',
            '(CAST(u.dt_expiracao_senha AS DATE) - CAST(NOW() AS DATE)) as tempo_expirar',
            $caseNome
        ];

        $select = $this
            ->select()
            ->setIntegrityCheck(false)
            ->from(array('u' => 'sistema.usuarios'), $campos)
            ->joinLeft(array('f' => 'sistema.funcionarios'), 'f.id_usuario = u.id', false)
            ->joinLeft(array('c' => 'sistema.corretores'), 'c.id_usuario = u.id', false)
            ->joinLeft(array('p' => 'sistema.prepostos'), 'p.id_usuario = u.id', false)
            ->joinLeft(array('a' => 'sistema.assessorias'), 'a.id_usuario = u.id', false)
            ->where('u.id = ?', $id);

        return $this->fetchRow($select);
	}

	public function getSenhasExpiradasOuPrestesAExpirar(int $expiraEm = 10): array
	{
		return $this->fetchAll(
			$this
				->select()
				->setIntegrityCheck(false)
				->from(
					array('u' => 'sistema.usuarios'),
					'id, fl_notificado_expiracao_senha, dt_expiracao_senha, ABS(CAST(dt_expiracao_senha AS DATE) - CAST(NOW() AS DATE)) AS expira_em')
				->joinLeft(
					array('f' => 'sistema.funcionarios'),
					'f.id_usuario = u.id',
					array('ds_email AS ds_email_funcionario', 'ds_nome_funcionario'))
				->joinLeft(
					array('c' => 'sistema.corretores'),
					'c.id_usuario = u.id',
					array('ds_email AS ds_email_corretor', 'ds_nome_corretor'))
				->joinLeft(
					array('p' => 'sistema.prepostos'),
					'p.id_usuario = u.id',
					array('ds_email AS ds_email_preposto', 'ds_nome_preposto', "CASE WHEN p.id is not null then id_corretor else 0 end as id_agrupamento"))
                ->joinLeft(
                    array('c_preposto' => 'sistema.corretores'),
                    'c_preposto.id = p.id_corretor',
                    array('ds_email AS ds_email_corretor_preposto', 'ds_nome_corretor as ds_nome_corretor_preposto'))
				->joinLeft(
					array('a' => 'sistema.assessorias'),
					'a.id_usuario = u.id',
					array('ds_email AS ds_email_assessoria', 'ds_nome_assessoria'))
				->where('u.fl_ativo IS TRUE')
				->where('u.fl_bloqueio_inatividade IS FALSE')
				->where("(CAST(u.dt_expiracao_senha AS DATE) - CAST(NOW() AS DATE)) <= {$expiraEm}")
		)->toArray();
	}

	public function getUsuariosMesesInativo(): array
	{
		$subqueryLogAcesso = $this->_db->select()
			->from(array('l' => 'log.log_acesso'), array('max(data_acesso) as data_acesso', 'id_usuario'))
			->group('l.id_usuario');

        $select = $this
            ->select()
            ->setIntegrityCheck(false)
            ->from(
                array('u' => 'sistema.usuarios'),
                'id, ds_nome_usuario, fl_notificado_bloqueio_inatividade')
            ->join(
                array('la' => $subqueryLogAcesso),
                'la.id_usuario = u.id',
                array(
                    'EXTRACT(year FROM age(now(),la.data_acesso))*12 + EXTRACT(month FROM age(now(),la.data_acesso)) AS meses_inativo',
                    'data_acesso'))
            ->joinLeft(
                array('f' => 'sistema.funcionarios'),
                'f.id_usuario = u.id',
                array('ds_email AS ds_email_funcionario', 'ds_nome_funcionario'))
            ->joinLeft(
                array('c' => 'sistema.corretores'),
                'c.id_usuario = u.id',
                array('ds_email AS ds_email_corretor', 'ds_nome_corretor'))
            ->joinLeft(
                array('p' => 'sistema.prepostos'),
                'p.id_usuario = u.id',
                array('ds_email AS ds_email_preposto', 'ds_nome_preposto', "CASE WHEN p.id is not null then id_corretor else 0 end as id_agrupamento"))
            ->joinLeft(
                array('c_preposto' => 'sistema.corretores'),
                'c_preposto.id = p.id_corretor',
                array('ds_email AS ds_email_corretor_preposto', 'ds_nome_corretor as ds_nome_corretor_preposto'))
            ->joinLeft(
                array('a' => 'sistema.assessorias'),
                'a.id_usuario = u.id',
                array('ds_email AS ds_email_assessoria', 'ds_nome_assessoria'))
            ->where('u.fl_ativo IS TRUE')
            ->where('u.fl_bloqueio_inatividade IS FALSE')
            ->where('u.id <> 2068')
            ->where("u.ds_nome_usuario <> 'vistoriador.teste1'")
            ->where("u.ds_nome_usuario <> 'vistoriador.teste6'");

		return $this->fetchAll($select)->toArray();
	}

	public static function isTipoUsuarioVistoriador(string $tipo): bool
	{
		return in_array(
			$tipo,
			[
				Sistema_Model_Usuarios::TIPO_USUARIO_VISTORIADOR,
				Sistema_Model_Usuarios::TIPO_USUARIO_MANAGER,
				Sistema_Model_Usuarios::TIPO_USUARIO_HELPER
			]
		);
	}

	public static function isTipoUsuarioIgnoraStatusConferido(string $tipo): bool
	{
		return in_array(
			$tipo,
			[
				Sistema_Model_Usuarios::TIPO_USUARIO_MANAGER,
				Sistema_Model_Usuarios::TIPO_USUARIO_HELPER
			]
		);
	}

    /**
     * Retorna se o usuário logado é do tipo corretor ou preposto
     * @return bool
     */
    public static function isUsuarioLogadoCorretorPreposto(): bool
    {
        return Sistema_Service_Corretor::isCorretor() || Sistema_Service_Preposto::isPreposto();
    }

    /**
     * @param string $email
     * @return Zend_Db_Table_Row_Abstract|null
     */
    public function getFuncionarioAgroByEmail(string $email) : ?Zend_Db_Table_Row_Abstract
    {
        $campos = ['su.id as id_usuario'];
        $select = $this->select()
            ->setIntegrityCheck(false)
            ->from(['su' => "{$this->_schema}.{$this->_name}"], $campos)
            ->join(['sf' => 'sistema.funcionarios'], 'sf.id_usuario = su.id', false)
            ->where('sf.ds_email = ?', $email)
            ->where('sf.id_empresa = ?', Sistema_Model_Empresas::AGROBRASIL);

        return $this->fetchRow($select);
    }
}
