<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require_once __DIR__ . '../../Db/Table/Adapter/Auth.php';

class Agro_Auth {
    private $config = null;
	private $Auth = null;
	protected static $db = null;
    protected static $exceptionUser = ['fabio.bertoldi', '4pp13.v41id4c40', 'g0og13.v41id4c40'];
	protected $email = null;
	private $error = array(
		'Token inválido ou expirado.',
		'Usuário ou senha inválido(s).',
		'Arquivo inexistente.',
		'Erro ao atualizar o status.',
        'Houve um problema ao salvar a vistoria!', // erro ao salvar vistoria
        'Vistoria salva com sucesso!',
        "Não foi possível gerar Laudo da Vistoria Prévia!",
		'Erro ao buscar as informações do banco do zoneamento!',
		'Este usuário já está vinculado a outro dispositivo. Entre em contato com atendimento.',
        'Usuário não habilitado.',
        'Erro ao informar vistoria limpa no tablet',
		'Erro ao receber arquivo de imagem',
		'Apenas um arquivo é aceito.'
	);

    /*
	* Verifica se já não existe um dispositivo vinculado ao usuário. 
	* Se não existir, vincula.
	* Se existir, verifcar se é o mesmo enviado
	**/
	protected function checkDevice($usuario, $deviceId) {

		// PARA TESTAR EM MAIS DE UM DISPOSITIVO
		if (in_array($usuario, self::$exceptionUser)) return true;

		if (!empty($usuario) && !empty($deviceId)) {

			$db_deviceid = self::$db->fetchOne("select deviceid from sistema.usuarios 
				where ds_nome_usuario = '{$usuario}'");

			if (empty($db_deviceid)) {
				try {
					self::$db->update('sistema.usuarios', array('deviceid' => $deviceId), "ds_nome_usuario = '{$usuario}'");
					return true;
				} catch (Exception $e) {
					return $e->getMessage();
				}
			} elseif ($deviceId == $db_deviceid) {
				return true;
			} else {
				return false;
			}
		}
	}

    public function __construct() {
		$os = strtoupper(substr(PHP_OS, 0, 3));
		$application_env = ($os == 'WIN') ? 'docker' : getenv('APPLICATION_ENV');
		$this->config = new Zend_Config_Ini(__DIR__ . '/../../../application/config/application.ini', $application_env);
	}

	protected function setDb() {
		$Adapter = Zend_Db::factory('PDO_PGSQL', $this->config->resources->db->params);
		Zend_Db_Table_Abstract::setDefaultAdapter($Adapter);
		self::$db = Zend_Db_Table::getDefaultAdapter();		
	}

    /**
	* Retorna a mensagem de erro do array de erros.
	*/
	protected function getError($idx) {
		return $this->error[$idx];
	}

    /*
	* Cria um token para acesso com expiração até o próximo dia
	**/
	protected function getToken($usuario) {
		$token = crypt($usuario.'$1$'.base64_encode('$1$#1th0uGHt14M4h4cker$2oi6').date('Ymd'), '$1$'.base64_encode('$1$#1th0uGHt14M4h4cker$2oi6'));
		return base64_encode($token);
	}

	/**
	* Verifica se existe o token informado para um usuário
	*/
	protected function checkToken($token = null) {
		try {

			$headrs = apache_request_headers();

			if (empty($headrs['Authorization'])) {
				throw new Exception('Autorization header não informado.', 401);
			}

			$token = explode(' ', $headrs['Authorization'])[1];

			$this->setDb();
			$Usuario = self::$db->select();
			$Usuario->from(array('u' => 'sistema.usuarios'), array('id','ds_nome_usuario','token', 'deviceid_sinistro'));
			$Usuario->where('u.token = ?', $token);

			$Row = self::$db->fetchRow($Usuario);

			if (is_array($Row)) {

				if ($Row['token'] === $this->getToken($Row['ds_nome_usuario'])) { 
					return $Row;
				} else {
					return false;
				}
			} else {
				return false;
			}
		} catch (Exception $e) {
			return $e->getMessage();
		}
	}

    protected function isUserAble($usuario) {
		//usuário de exceção
		if (in_array($usuario, self::$exceptionUser)) {
			return true;
		}

        $this->setDb();
        $Usuario = self::$db->select();
        $Usuario->from(array('u' => 'sistema.usuarios'), array('id','ds_nome_usuario','token'));
        $Usuario->where('u.ds_nome_usuario = ?', $usuario);
        $Usuario->where('u.fl_liberado_tablet_previa = ?', true);

        $Row = self::$db->fetchRow($Usuario);

		if (is_array($Row)) {
			return true;
		}

		return false;
	}

	/**
	* Valida usuário e senha e devolve token
	*/
	private function checkIdentity($usuario, $senha) {
		$filter = new Zend_Filter_StripTags();
		$f_usuario = $filter->filter($usuario);
		$f_senha = $filter->filter($senha);

		$this->setDb();
		$this->Auth = Zend_Auth::getInstance();

		$AuthAdapter = new Agro_Db_Table_Adapter_Auth();
		$AuthAdapter->setTablename('sistema.v_login');
		$AuthAdapter->setIdentityColumn('ds_nome_usuario');
		$AuthAdapter->setCredentialColumn('ds_senha');
		$AuthAdapter->setIdentity($f_usuario);
		$AuthAdapter->setCredential($f_senha);

		if ($this->Auth->authenticate($AuthAdapter)->isValid()) {
			$data = $AuthAdapter->getResultRowObject(null, 'ds_senha');
			$this->Auth->getStorage()->write($data);

			return true;
		} else {
			return false;
		}
	}

    /**
     * Autentica o usuário
     * 
     * @param string usuario
     * @param string senha
     * @param string deviceId
     * @return array
     */
    public function auth($usuario, $senha, $deviceId = "")
    {
		$usuario = trim($usuario); 
		$senha = trim($senha);

        if (!$this->checkIdentity($usuario, $senha)) {
			http_response_code(401);
            return array('status' => false, 'message' => $this->getError(1));
        }

        //valida se o usuário está habilitado
        if (!$this->isUserAble($usuario)) {
			http_response_code(401);
            return array('status' => false, 'message' => $this->getError(9));
        }

        $token = $this->getToken($usuario, $senha);
        if(!is_array($this->checkToken($token))) {
            //insere token para o usuário
            try {
                self::$db->update('sistema.usuarios', array('token' => $token), "ds_nome_usuario = '$usuario'");
            } catch (Exception $e) {
				http_response_code(500);
                return "Erro ao gerar o token.";
            }
        }

        if (!$this->checkDevice($usuario, $deviceId)) {
			http_response_code(401);
            return array('status' => false, 'message' => $this->getError(8));
        }

		http_response_code(200);
        return array('status' => true, 'token' => $token);
    }
}