package hr.com.port.ips.eracun.dao;

import hr.com.port.functions.Functions;
import hr.com.port.ips.eracun.modeli.EracunDokumentLog;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;

public class EracunDokumentLogDao {
	
	static Logger logger = Logger.getLogger(EracunDokumentLogDao.class);

    public void insert(EracunDokumentLog log, Connection conn) {
        String sql = "INSERT INTO eracun_dokument_log (" +
            "izlazni, godina, posrednik, vrsta_dokumenta, onu, opp, broj, " +
            "electronic_id, " +
            "lokalni_status_id, lokalni_status_naziv, " +
            "transportni_status_id, transportni_status_naziv, " +
            "procesni_status_id, procesni_status_naziv, " +
            "datum_statusa, datum_promjene, " +
            "poruka_greske, opis, putanja_xml, izvor, akcija, oib_operatera" +
            ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

        try (PreparedStatement ps = conn.prepareStatement(sql)) {
			ps.setBoolean(1,  log.isIzlazni());
			ps.setInt(2,  log.getGodina());
			ps.setInt(3,  log.getPosrednik());
			ps.setInt(4,  log.getVrstaDokumenta());
			ps.setInt(5,  log.getOnu());
			ps.setInt(6,  log.getOpp());
			ps.setInt(7,  log.getBroj());
			ps.setObject(8,  log.getElectronicId(), java.sql.Types.BIGINT);
			ps.setObject(9,  log.getLokalniStatusId(),  java.sql.Types.INTEGER);
			ps.setString(10,  log.getLokalniStatusNaziv());
			ps.setObject(11, log.getTransportniStatusId(),  java.sql.Types.INTEGER);
			ps.setString(12, log.getTransportniStatusNaziv());
			ps.setObject(13, log.getProcesniStatusId(),  java.sql.Types.INTEGER);
			ps.setString(14, log.getProcesniStatusNaziv());
			ps.setTimestamp(15, log.getDatumStatusa());
			ps.setTimestamp(16, log.getDatumPromjene());
			ps.setString(17, log.getPorukaGreske());
			ps.setString(18, log.getOpis());
			ps.setString(19, log.getPutanjaXml());
			ps.setString(20, log.getIzvor());
			ps.setString(21, log.getAkcija());
			ps.setString(22, log.getOibOperatera());			
			ps.executeUpdate();
		} catch (SQLException ex) {
	        logger.error(new Functions().logging(ex));
	    }
    }
	
	public void upsert(EracunDokumentLog log, Connection conn) {
		final String sql =
			"INSERT INTO eracun_dokument_log (" +
			"  izlazni, godina, posrednik, vrsta_dokumenta, onu, opp, broj, " +
			"  electronic_id, " +
			"  lokalni_status_id, lokalni_status_naziv, " +
			"  transportni_status_id, transportni_status_naziv, " +
			"  procesni_status_id, procesni_status_naziv, " +
			"  datum_statusa, datum_promjene, " +
			"  poruka_greske, opis, putanja_xml, izvor, akcija, oib_operatera" +
			") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) " +
			"ON DUPLICATE KEY UPDATE " +
			// snapshot polja – osvježi uvijek na VALUES(...)
			"  izlazni=VALUES(izlazni), " +
			"  godina=VALUES(godina), " +
			"  posrednik=VALUES(posrednik), " +
			"  vrsta_dokumenta=VALUES(vrsta_dokumenta), " +
			"  onu=VALUES(onu), " +
			"  opp=VALUES(opp), " +
			"  broj=VALUES(broj), " +
			"  lokalni_status_id=VALUES(lokalni_status_id), " +
			"  lokalni_status_naziv=VALUES(lokalni_status_naziv), " +
			"  transportni_status_id=VALUES(transportni_status_id), " +
			"  transportni_status_naziv=VALUES(transportni_status_naziv), " +
			"  procesni_status_id=VALUES(procesni_status_id), " +
			"  procesni_status_naziv=VALUES(procesni_status_naziv), " +
			// vremenska i tekstualna polja – ne prepisuj s nullom
			"  datum_statusa=COALESCE(VALUES(datum_statusa), datum_statusa), " +
			"  datum_promjene=COALESCE(VALUES(datum_promjene), datum_promjene), " +
			"  poruka_greske=COALESCE(VALUES(poruka_greske), poruka_greske), " +
			"  opis=COALESCE(VALUES(opis), opis), " +
			"  putanja_xml=COALESCE(VALUES(putanja_xml), putanja_xml), " +
			// ključna polja (electronic_id, izvor, akcija) ne diramo
			"  oib_operatera=COALESCE(VALUES(oib_operatera), oib_operatera)";

		try (PreparedStatement ps = conn.prepareStatement(sql)) {
			int i = 1;
			ps.setBoolean(i++, log.isIzlazni());
			ps.setInt(i++,     log.getGodina());
			ps.setInt(i++,     log.getPosrednik());
			ps.setInt(i++,     log.getVrstaDokumenta());
			ps.setInt(i++,     log.getOnu());
			ps.setInt(i++,     log.getOpp());
			ps.setInt(i++,     log.getBroj());
			ps.setObject(i++,  log.getElectronicId(), java.sql.Types.BIGINT);

			ps.setObject(i++,  log.getLokalniStatusId(),     java.sql.Types.INTEGER);
			ps.setString(i++,  log.getLokalniStatusNaziv());
			ps.setObject(i++,  log.getTransportniStatusId(), java.sql.Types.INTEGER);
			ps.setString(i++,  log.getTransportniStatusNaziv());
			ps.setObject(i++,  log.getProcesniStatusId(),    java.sql.Types.INTEGER);
			ps.setString(i++,  log.getProcesniStatusNaziv());

			ps.setTimestamp(i++, log.getDatumStatusa());
			ps.setTimestamp(i++, log.getDatumPromjene());

			ps.setString(i++,  log.getPorukaGreske());
			ps.setString(i++,  log.getOpis());
			ps.setString(i++,  log.getPutanjaXml());
			ps.setString(i++,  log.getIzvor());
			ps.setString(i++,  log.getAkcija());
			ps.setString(i++,  log.getOibOperatera());

			ps.executeUpdate();
		} catch (SQLException ex) {
			logger.error(new Functions().logging(ex));
		}
	}
	
	public List<EracunDokumentLog> findByElectronicId(long electronicId, boolean izlazni, Connection... defaultConnection) {
		final String sql = "SELECT * FROM eracun_dokument_log WHERE electronic_id=? AND izlazni=? ORDER BY datum_promjene DESC, id DESC";

		Connection conn = null;
		boolean external = defaultConnection != null && defaultConnection.length > 0 && defaultConnection[0] != null;
		List<EracunDokumentLog> list = new ArrayList<EracunDokumentLog>();
		try {
			conn = external ? defaultConnection[0] : new hr.com.port.connectionPool.__Pool(null).getConnection();
			try (PreparedStatement ps = conn.prepareStatement(sql)) {
				ps.setLong(1, electronicId);
				ps.setBoolean(2, izlazni);
				try (ResultSet rs = ps.executeQuery()) {
					while (rs.next()) {
						EracunDokumentLog l = new EracunDokumentLog();
						l.setId(rs.getLong("id"));
						l.setIzlazni(rs.getBoolean("izlazni"));
						l.setGodina(rs.getInt("godina"));
						l.setPosrednik(rs.getInt("posrednik"));
						l.setVrstaDokumenta(rs.getInt("vrsta_dokumenta"));
						l.setOnu(rs.getInt("onu"));
						l.setOpp(rs.getInt("opp"));
						l.setBroj(rs.getInt("broj"));
						l.setElectronicId(rs.getLong("electronic_id"));
						l.setLokalniStatusId((Integer) rs.getObject("lokalni_status_id"));
						l.setLokalniStatusNaziv(rs.getString("lokalni_status_naziv"));
						l.setTransportniStatusId((Integer) rs.getObject("transportni_status_id"));
						l.setTransportniStatusNaziv(rs.getString("transportni_status_naziv"));
						l.setProcesniStatusId((Integer) rs.getObject("procesni_status_id"));
						l.setProcesniStatusNaziv(rs.getString("procesni_status_naziv"));
						l.setDatumStatusa(rs.getTimestamp("datum_statusa"));
						l.setDatumPromjene(rs.getTimestamp("datum_promjene"));
						l.setPorukaGreske(rs.getString("poruka_greske"));
						l.setOpis(rs.getString("opis"));
						l.setPutanjaXml(rs.getString("putanja_xml"));
						l.setIzvor(rs.getString("izvor"));
						l.setAkcija(rs.getString("akcija"));
						l.setOibOperatera(rs.getString("oib_operatera"));
						list.add(l);
					}
				}
			}
		} catch (SQLException ex) {
			logger.error(new Functions().logging(ex));
		} finally {
			if (!external && conn != null) try { conn.close(); } catch (SQLException ignore) {}
		}
		return list;
	}
	
	public void insertJson(long electronicId, String izvor, String akcija, com.google.gson.JsonObject detaljiJson, Connection conn) throws SQLException {
		final String sql = "INSERT INTO eracun_dokument_log " +
				"(electronic_id, izvor, akcija, datum_promjene, detalji) " +
				"VALUES (?, ?, ?, ?, ?)";
		try (PreparedStatement ps = conn.prepareStatement(sql)) {
			ps.setLong(1, electronicId);
			ps.setString(2, izvor);
			ps.setString(3, akcija);
			ps.setTimestamp(4, new java.sql.Timestamp(System.currentTimeMillis()));
			ps.setString(5, detaljiJson != null ? detaljiJson.toString() : null);
			ps.executeUpdate();
		}
	}
	
	public void upsertJson(long electronicId, String izvor, String akcija, String detaljiJson, Connection conn) {
		final String sql =
			"INSERT INTO eracun_dokument_log (electronic_id, izvor, akcija, datum_promjene, detalji) " +
			"VALUES (?, ?, ?, NOW(), ?) " +
			"ON DUPLICATE KEY UPDATE " +
			"  detalji=VALUES(detalji), " +
			"  datum_promjene=NOW()";
		try (PreparedStatement ps = conn.prepareStatement(sql)) {
			ps.setLong(1, electronicId);
			ps.setString(2, izvor);
			ps.setString(3, akcija);
			ps.setString(4, detaljiJson);
			ps.executeUpdate();
		} catch (SQLException ex) {
			logger.error(new Functions().logging(ex));
		}
	}	
	
	public boolean exists(long eid, String izvor, String akcija, Connection conn) throws SQLException {
		final String sql = "SELECT 1 FROM eracun_dokument_log WHERE electronic_id=? AND izvor=? AND akcija=? LIMIT 1";
		try (PreparedStatement ps = conn.prepareStatement(sql)) {
			ps.setLong(1, eid); ps.setString(2, izvor); ps.setString(3, akcija);
			try (ResultSet rs = ps.executeQuery()) { return rs.next(); }
		}
	}
}