package com.softgraf.model.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.softgraf.control.Sistema;
import com.softgraf.model.ClienteProperty;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class ClienteDAO implements AbstractGenericDAO<ClienteProperty>{

	private Connection conexao;
	
	public ClienteDAO(Connection conexao) {
		this.conexao = conexao;
	}
	
	@Override
	public boolean inserir(ClienteProperty cliente) {
		int retorno = 0;
		
		// id = auto-incremento
		String sql = "INSERT INTO cliente (tipo, nome, cpf_cnpj, email, "+
				"fone, cidade, estado, rua, bairro, cep) " +
				"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
		
		try {
			// compila a sentença sql
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setBoolean(1, cliente.getTipo() == 'F');
			pst.setString(2, cliente.getNome());
			pst.setString(3, cliente.getCpfCnpj());
			pst.setString(4, cliente.getEmail());
			pst.setString(5, cliente.getFone());
			pst.setString(6, cliente.getCidade());
			pst.setString(7, cliente.getEstado());
			pst.setString(8, cliente.getRua());
			pst.setString(9, cliente.getBairro());
			pst.setString(10, cliente.getCep());
			retorno = pst.executeUpdate();
			pst.close();
			
		} catch (SQLException e) {
			Sistema.showException("Erro de sentença SQL ao inserir cliente", e);
		}
		
		return retorno > 0;
	}

	@Override
	public boolean remover(int id) {
		int retorno = 0;
		String sql = "DELETE FROM cliente WHERE id=?";
		
		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setInt(1, id);
			retorno = pst.executeUpdate();
			pst.close();
			
		} catch (SQLException e) {
			Sistema.showException("Erro de sentença SQL ao remover cliente", e);
		}
		
		return retorno > 0;
	}

	@Override
	public boolean atualizar(int id, ClienteProperty cliente) {
		int retorno = 0;
		String sql = "UPDATE cliente SET tipo=?, nome=?, cpf_cnpj=?, " +
					 "email=?, fone=?, cidade=?, estado=?, rua=?, " +
					 "bairro=?, cep=? WHERE id=?";
		
		try {
			
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setBoolean(1, cliente.getTipo() == 'F');
			pst.setString(2, cliente.getNome());
			pst.setString(3, cliente.getCpfCnpj());
			pst.setString(4, cliente.getEmail());
			pst.setString(5, cliente.getFone());
			pst.setString(6, cliente.getCidade());
			pst.setString(7, cliente.getEstado());
			pst.setString(8, cliente.getRua());
			pst.setString(9, cliente.getBairro());
			pst.setString(10, cliente.getCep());
			pst.setInt(11, id);
			retorno = pst.executeUpdate();
			pst.close();
		
		} catch (SQLException e) {
			Sistema.showException("Erro de sentença SQL ao atualizar cliente", e);
		}
		
		return retorno > 0;
	}

	// Listar por nome
	public ObservableList<ClienteProperty> listarPorNome(String nome,
			int quant){
		
		String sql = "SELECT * FROM cliente WHERE nome LIKE ? LIMIT ?";
		
		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setString(1, "%" + nome + "%");
			pst.setInt(2, quant);
			return listar(pst);
			
		} catch (SQLException e) {
			Sistema.showException("Erro de senteça SQL ao listar clientes por nome", e);
		}
		
		return null;
	}
	
	// Listar por CPF
	public ObservableList<ClienteProperty> listarPorCpf(String cpf,
			int quant){
		
		String sql = "SELECT * FROM cliente WHERE tipo=1 AND cpf_cnpj LIKE ? LIMIT ?";

		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setString(1, "%" + cpf + "%");
			pst.setInt(2, quant);
			return listar(pst);
			
		} catch (SQLException e){
			Sistema.showException("Erro de setença SQL ao listar clientes por CPF", e);
		}
		
		return null;
	}
	
	// Listar por CNPJ
	public ObservableList<ClienteProperty> listarPorCnpj (String cnpj,
			int quant){
		
		String sql = "SELECT * FROM cliente WHERE tipo=0 AND cpf_cnpj LIKE ? LIMIT ?";
		
		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setString(1, "%" + cnpj + "%");
			pst.setInt(2, quant);
			return listar(pst);
			
		} catch (SQLException e){
			Sistema.showException("Erro de setença SQL ao listar clientes por CNPJ", e);
		}
		
		return null;
	}
	
	
	@Override
	public ObservableList<ClienteProperty> listarPorId(int idInicial, int quant) {
		String sql = "SELECT * FROM cliente WHERE id >= ? LIMIT ?";
		

		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setInt(1, idInicial);
			pst.setInt(2, quant);
			return listar(pst);
			
		} catch (SQLException e) {
			Sistema.showException("Erro de sentença SQL ao listar clientes por id", e);
		}
		
		return null;
	}

	// listagem genérica
	private ObservableList<ClienteProperty> listar (PreparedStatement pst) throws SQLException {
		ObservableList<ClienteProperty> listaClientes = 
									FXCollections.observableArrayList();
		ClienteProperty cliente;
		ResultSet rs = pst.executeQuery();
		
		while (rs.next()){
			cliente = resultSet2Cliente(rs); 
			listaClientes.add(cliente);
		}
		
		rs.close();
		pst.close();
		
		return listaClientes.isEmpty() ? null : listaClientes;
	}
	
	
	// retorna um cliente a partir de um objeto ResultSet
	private ClienteProperty resultSet2Cliente (ResultSet rs) throws SQLException{
		return new ClienteProperty()
				.codigo(rs.getInt("id"))
				.tipo(rs.getBoolean("tipo") ? 'F' : 'J')
				.nome(rs.getString("nome"))
				.cpfCnpj(rs.getString("cpf_cnpj"))
				.email(rs.getString("email"))
				.fone(rs.getString("fone"))
				.cidade(rs.getString("cidade"))
				.cep(rs.getString("cep"))
				.estado(rs.getString("estado"))
				.rua(rs.getString("rua"))
				.bairro(rs.getString("bairro"));		
	}
	
	@Override
	public ClienteProperty buscar(int id) {
		ClienteProperty cliente = null;
		String sql = "SELECT * FROM cliente WHERE id = ?";
		
		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			pst.setInt(1, id);
			ResultSet rs = pst.executeQuery();
			
			if (rs.next()){
				cliente = resultSet2Cliente(rs);
			}
			
			rs.close();
			pst.close();
			
		} catch (SQLException e) {
			Sistema.showException("Erro de sentença SQL ao busar clientes", e);
		}
		
		return cliente;
	}
	
	@Override
	public int contar() {
		String sql = "SELECT COUNT(*) AS quant FROM cliente";
		int quant = 0;
		
		try {
			PreparedStatement pst = conexao.prepareStatement(sql);
			ResultSet rs = pst.executeQuery(sql);
			rs.last();
			quant = rs.getInt("quant");
			rs.close();
			pst.close();
			
		} catch (Exception e) {
			Sistema.showException("Erro de sentença SQL ao contar registros", e);
		}
		
		return quant;
	}

}
