package marketing.heyday.hartmann.fotodocumentation.core.service;

import java.text.ParseException;
import java.util.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jakarta.annotation.security.PermitAll;
import jakarta.ejb.LocalBean;
import jakarta.ejb.Stateless;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.*;
import marketing.heyday.hartmann.fotodocumentation.core.model.Customer;
import marketing.heyday.hartmann.fotodocumentation.core.model.Picture;
import marketing.heyday.hartmann.fotodocumentation.core.query.Param;
import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerListValue;
import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue;
import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerValue;

/**
 * 
 * <p>Copyright: Copyright (c) 2024</p>
 * <p>Company: heyday Marketing GmbH</p>
 * @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
 * @version 1.0
 * 
 * created: 19 Jan 2026
 */
@Stateless
@LocalBean
@PermitAll
public class CustomerPictureService extends AbstractService {
	private static final Log LOG = LogFactory.getLog(CustomerPictureService.class);

	public boolean addCustomerPicture(CustomerPictureValue customerPictureValue) {
		Optional<Customer> customerOpt = queryService.callNamedQuerySingleResult(Customer.FIND_BY_NUMBER, new Param(Customer.PARAM_NUMBER, customerPictureValue.customerNumber()));
		Customer customer = customerOpt.orElseGet(() -> new Customer.Builder().customerNumber(customerPictureValue.customerNumber()).name(customerPictureValue.pharmacyName()).build());
		customer = entityManager.merge(customer);

		Picture picture = new Picture.Builder().customer(customer).username(customerPictureValue.username())
				.category(customerPictureValue.category())
				.comment(customerPictureValue.comment())
				.image(customerPictureValue.base64String())
				.pictureDate(customerPictureValue.date()).build();
		customer.getPictures().add(picture);

		entityManager.persist(picture);
		entityManager.flush();
		return true;
	}

	// query = search for name, number and date
	public List<CustomerListValue> getAll(String queryStr, String startsWith) {
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Customer> criteriaQuery = builder.createQuery(Customer.class);
		Root<Customer> customerRoot = criteriaQuery.from(Customer.class);

		criteriaQuery = criteriaQuery.select(customerRoot).distinct(true);

		List<Predicate> predicates = new ArrayList<>();

		if (StringUtils.isNotBlank(startsWith)) {
			String param = startsWith.toLowerCase() + "%";
			var pred = builder.like(builder.lower(customerRoot.get("name")), param);
			predicates.add(pred);
		}

		if (StringUtils.isNotBlank(queryStr)) {

			// check if it contains a date
			Date date = null;
			try {
				date = DateUtils.parseDate(queryStr, Locale.GERMAN, "dd.MM.yyyy", "d.M.yyyy", "dd.MM.yy", "d. MMMM yyyy", "dd MMMM yyyy", "dd-MM-yyyy");

				Calendar cal = Calendar.getInstance();
				cal.setTime(date);
				cal.set(Calendar.HOUR_OF_DAY, 0);
				cal.set(Calendar.MINUTE, 0);
				cal.set(Calendar.SECOND, 0);
				cal.set(Calendar.MILLISECOND, 0);
				Date startOfDay = cal.getTime();

				cal.set(Calendar.HOUR_OF_DAY, 23);
				cal.set(Calendar.MINUTE, 59);
				cal.set(Calendar.SECOND, 59);
				cal.set(Calendar.MILLISECOND, 999);
				Date endOfDay = cal.getTime();

				Fetch<Customer, Picture> picturesFetch = customerRoot.fetch("pictures", JoinType.LEFT);
				@SuppressWarnings("unchecked")
				Join<Customer, Picture> pictures = (Join<Customer, Picture>) picturesFetch;

				var predicateDate = builder.between(pictures.get("pictureDate"), startOfDay, endOfDay);
				predicates.add(predicateDate);

			} catch (ParseException e) {
				LOG.trace("Failed to find date in queryStr " + queryStr);
			}

			if (date == null) {
				String param = "%" + StringUtils.trimToEmpty(queryStr).toLowerCase() + "%";
				var predicateName = builder.like(builder.lower(customerRoot.get("name")), param);
				var predicateNr = builder.like(builder.lower(customerRoot.get("customerNumber")), param);

				var pred = builder.or(predicateName, predicateNr);
				predicates.add(pred);
			}
		}

		if (predicates.size() == 1) {
			criteriaQuery = criteriaQuery.where(predicates.getFirst());
		} else if (predicates.size() > 1) {
			criteriaQuery = criteriaQuery.where(builder.and(predicates.toArray(new Predicate[0])));
		}

		TypedQuery<Customer> typedQuery = entityManager.createQuery(criteriaQuery);
		List<Customer> customers = typedQuery.getResultList();
		customers.forEach(c -> c.getPictures().size());
		return customers.parallelStream().map(CustomerListValue::builder).toList();
	}

	public CustomerValue get(Long id) {
		Customer customer = entityManager.find(Customer.class, id);
		if (customer == null) {
			return null;
		}

		return CustomerValue.builder(customer);
	}
}
