package de.jottyfan.camporganizer.module.business.outlay;

import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMP;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_LOCATION;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_SALES;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep8;
import org.jooq.Record10;
import org.jooq.Record11;
import org.jooq.Record4;
import org.jooq.SelectConditionStep;
import org.jooq.SelectSeekStep1;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import de.jottyfan.camporganizer.db.jooq.tables.records.TSalesRecord;
import de.jottyfan.camporganizer.module.business.outlay.model.CampBean;
import de.jottyfan.camporganizer.module.business.outlay.model.OutlayBean;
import jakarta.validation.Valid;

/**
 *
 * @author jotty
 *
 */
@Repository
@Transactional(transactionManager = "transactionManager")
public class OutlayRepository {
	private static final Logger LOGGER = LogManager.getLogger(OutlayRepository.class);

	@Autowired
	private DSLContext jooq;

	/**
	 * get all camps from the database
	 *
	 * @return a list of camps; an empty list at least
	 */
	public List<CampBean> getAllCamps() {
		SelectSeekStep1<Record4<Integer, String, LocalDateTime, String>, LocalDateTime> sql = jooq
		// @formatter:off
			.select(T_CAMP.PK, T_CAMP.NAME, T_CAMP.ARRIVE, T_LOCATION.NAME)
			.from(T_CAMP)
			.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION))
			.orderBy(T_CAMP.ARRIVE.desc());
		// @formatter:on
		LOGGER.trace(sql.toString());
		List<CampBean> list = new ArrayList<>();
		Iterator<Record4<Integer, String, LocalDateTime, String>> i = sql.fetch().iterator();
		while (i.hasNext()) {
			Record4<Integer, String, LocalDateTime, String> r = i.next();
			String name = String
					.format("%s %s %d", r.get(T_CAMP.NAME), r.get(T_LOCATION.NAME), r.get(T_CAMP.ARRIVE).getYear()).trim();
			list.add(CampBean.of(r.get(T_CAMP.PK)).withCampname(name));
		}
		return list;
	}

	public List<OutlayBean> getListOf(String username, Integer campId) {
		SelectConditionStep<Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String>> sql = jooq
		// @formatter:off
			.select(T_SALES.PK,
					    T_SALES.TRADER,
					    T_CAMP.NAME,
					    T_CAMP.ARRIVE,
					    T_LOCATION.NAME,
					    T_SALES.CASH,
					    T_SALES.BUYDATE,
					    T_SALES.PROVIDER,
					    T_SALES.RECIPENUMBER,
					    T_SALES.INCREDIENTS,
					    T_SALES.RECIPENOTE)
			.from(T_SALES)
			.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_SALES.FK_CAMP))
			.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION))
			.where(username == null ? DSL.trueCondition() : T_SALES.PROVIDER.eq(username))
			.and(campId == null ? DSL.trueCondition() : T_SALES.FK_CAMP.eq(campId));
		// @formatter:on
		LOGGER.trace(sql);
		List<OutlayBean> list = new ArrayList<>();
		Iterator<Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String>> i = sql.fetch()
				.iterator();
		while (i.hasNext()) {
			Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String> r = i.next();
			String campname = String
					.format("%s %s %d", r.get(T_CAMP.NAME), r.get(T_LOCATION.NAME), r.get(T_CAMP.ARRIVE).getYear()).trim();
			OutlayBean bean = new OutlayBean();
			bean.setId(r.get(T_SALES.PK));
			bean.setTrader(r.get(T_SALES.TRADER));
			bean.setCampname(campname);
			bean.setProvider(r.get(T_SALES.PROVIDER));
			bean.setCash(r.get(T_SALES.CASH));
			bean.setBuydate(r.get(T_SALES.BUYDATE));
			bean.setRecipenumber(r.get(T_SALES.RECIPENUMBER));
			bean.setIngredients(r.get(T_SALES.INCREDIENTS));
			bean.setRecipenote(r.get(T_SALES.RECIPENOTE));
			list.add(bean);
		}
		return list;
	}

	public void addBean(@Valid OutlayBean bean) {
		InsertValuesStep8<TSalesRecord, LocalDateTime, BigDecimal, Integer, String, String, String, String, String> sql = jooq
		// @formatter:off
			.insertInto(T_SALES,
					        T_SALES.BUYDATE,
					        T_SALES.CASH,
					        T_SALES.FK_CAMP,
					        T_SALES.INCREDIENTS,
					        T_SALES.PROVIDER,
					        T_SALES.RECIPENOTE,
					        T_SALES.RECIPENUMBER,
					        T_SALES.TRADER)
			.values(bean.getBuydate(), bean.getCash(), bean.getFkCamp(), bean.getIngredients(), bean.getProvider(), bean.getRecipenote(), bean.getRecipenumber(), bean.getTrader());
		// @formatter:on
		LOGGER.trace(sql);
		sql.execute();
	}

	public void updateBean(@Valid OutlayBean bean) {
		UpdateConditionStep<TSalesRecord> sql = jooq
		// @formatter:off
			.update(T_SALES)
			.set(T_SALES.BUYDATE, bean.getBuydate())
			.set(T_SALES.CASH, bean.getCash())
			.set(T_SALES.FK_CAMP, bean.getFkCamp())
			.set(T_SALES.INCREDIENTS, bean.getIngredients())
			.set(T_SALES.PROVIDER, bean.getProvider())
			.set(T_SALES.RECIPENOTE, bean.getRecipenote())
			.set(T_SALES.RECIPENUMBER, bean.getRecipenumber())
			.set(T_SALES.TRADER, bean.getTrader())
			.where(T_SALES.PK.eq(bean.getId()));
		// @formatter:on
		LOGGER.trace(sql);
		sql.execute();
	}

	public OutlayBean getBeanIfAllowedFor(String username, Integer id) {
		SelectConditionStep<Record10<Integer, String, Integer, BigDecimal, LocalDateTime, String, String, String, String, String>> sql = jooq
		// @formatter:off
			.select(T_SALES.PK,
					    T_SALES.TRADER,
					    T_SALES.FK_CAMP,
					    T_SALES.CASH,
					    T_SALES.BUYDATE,
					    T_SALES.INCREDIENTS,
					    T_SALES.PROVIDER,
					    T_SALES.RECIPENOTE,
					    T_SALES.RECIPENUMBER,
					    T_SALES.TRADER)
			.from(T_SALES)
			.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_SALES.FK_CAMP))
			.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION))
			.where(T_SALES.PROVIDER.eq(username))
			.and(T_SALES.PK.eq(id));
		// @formatter:on
		LOGGER.trace(sql);
		Record10<Integer, String, Integer, BigDecimal, LocalDateTime, String, String, String, String, String> r = sql
				.fetchOne();
		if (r == null) {
			return null;
		} else {
			OutlayBean bean = new OutlayBean();
			bean.setId(r.get(T_SALES.PK));
			bean.setBuydate(r.get(T_SALES.BUYDATE));
			bean.setCash(r.get(T_SALES.CASH));
			bean.setFkCamp(r.get(T_SALES.FK_CAMP));
			bean.setIngredients(r.get(T_SALES.INCREDIENTS));
			bean.setProvider(r.get(T_SALES.PROVIDER));
			bean.setRecipenote(r.get(T_SALES.RECIPENOTE));
			bean.setRecipenumber(r.get(T_SALES.RECIPENUMBER));
			bean.setTrader(r.get(T_SALES.TRADER));
			return bean;
		}
	}

	public void deleteBeanIfAllowedFor(String username, Integer id) {
		DeleteConditionStep<TSalesRecord> sql = jooq
		// @formatter:off
			.deleteFrom(T_SALES)
			.where(T_SALES.PROVIDER.eq(username))
			.and(T_SALES.PK.eq(id));
		// @formatter:off
		LOGGER.trace(sql);
		sql.execute();
	}

}
