package de.jottyfan.camporganizer.module.admin;

import static de.jottyfan.camporganizer.db.jooq.Tables.T_DOCUMENT;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import de.jottyfan.camporganizer.db.jooq.enums.EnumDocument;
import de.jottyfan.camporganizer.module.admin.model.CampBean;
import de.jottyfan.camporganizer.module.admin.model.CampDocumentBean;
import de.jottyfan.camporganizer.module.admin.model.DocumentBean;
import de.jottyfan.camporganizer.module.admin.model.LocationBean;
import de.jottyfan.camporganizer.module.admin.model.ProfileBean;
import de.jottyfan.camporganizer.module.mail.MailBean;
import de.jottyfan.camporganizer.module.mail.MailRepository;
import jakarta.validation.Valid;

/**
 *
 * @author jotty
 *
 */
@Service
public class AdminService {
	private static final Logger LOGGER = LogManager.getLogger(AdminService.class);

	@Autowired
	private MailRepository mailRepository;

	@Autowired
	private AdminRepository adminRepository;

	public void sendMail(@Valid MailBean bean) {
		mailRepository.sendMail(bean);
	}

	/**
	 * get all documents
	 *
	 * @return a list of documents; an empty one at least
	 */
	public List<DocumentBean> getAllDocuments() {
		return adminRepository.getAllDocuments();
	}

	/**
	 * get document from the database
	 *
	 * @param id the ID of the document
	 * @return the document or null
	 */
	public DocumentBean getDocument(Integer id) {
		return adminRepository.getDocument(id);
	}

	/**
	 * upsert the document bean
	 *
	 * @param bean the bean
	 * @return the number of affected database lines
	 */
	public Integer updateDocument(@Valid DocumentBean bean) {
		try {
			bean.encodeUpload();
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
		}
		return adminRepository.upsert(bean);
	}

	/**
	 * delete document with id from the database
	 *
	 * @param id the ID of the document
	 * @return the number of affected database lines
	 */
	public Integer deleteDocument(Integer id) {
		return adminRepository.deleteDocument(id);
	}

	/**
	 * get all locations
	 *
	 * @return the locations
	 */
	public List<LocationBean> getLocations() {
		return adminRepository.getLocations();
	}

	/**
	 * get the location of id
	 *
	 * @param id the id
	 * @return the location or null
	 */
	public LocationBean getLocation(Integer id) {
		return adminRepository.getLocation(id);
	}

	/**
	 * upsert the bean
	 *
	 * @param bean the bean
	 */
	public void upsertLocation(@Valid LocationBean bean) {
		adminRepository.upsertLocation(bean);
	}

	/**
	 * delete the location
	 *
	 * @param id the ID of the location
	 */
	public void deleteLocation(Integer id) {
		// TODO: if a location is still in use by a camp, forbid deleting it
		adminRepository.deleteLocation(id);
	}

	/**
	 * get all documents that fit to the location definitions
	 *
	 * @return the location documents
	 */
	public List<DocumentBean> getLocationDocuments() {
		return adminRepository.getAllDocumentsWith(T_DOCUMENT.DOCTYPE.eq(EnumDocument.location));
	}

	/**
	 * get all documents that fit to the camp definitions
	 *
	 * @return the camp documents
	 */
	public List<DocumentBean> getCampDocuments() {
		return adminRepository.getAllDocumentsWith(T_DOCUMENT.DOCTYPE.eq(EnumDocument.camp));
	}

	/**
	 * get all camp beans from the database
	 *
	 * @return all camp beans; an empty list at least
	 */
	public List<CampBean> getAllCamps() {
		return adminRepository.getAllCamps();
	}

	/**
	 * get all profiles from the db
	 *
	 * @return the profiles
	 */
	public List<ProfileBean> getProfiles() {
		return adminRepository.getProfiles();
	}

	/**
	 * get the camp of id
	 *
	 * @param id the ID of the camp
	 * @return the camp or null
	 */
	public CampBean getCamp(Integer id) {
		return adminRepository.getCamp(id);
	}

	/**
	 * upsert the camp
	 *
	 * @param bean the bean
	 * @return the error message, if any
	 */
	public String upsertCamp(@Valid CampBean bean) {
		return adminRepository.upsertCamp(bean);
	}

	/**
	 * delete the camp and all of its dependencies
	 *
	 * @param id the ID of the camp
	 * @return the error message, if any
	 */
	public String deleteCamp(Integer id) {
		return adminRepository.deleteCamp(id);
	}

	/**
	 * get all camp documents
	 *
	 * @return a list of camp documents; an empty list at least
	 */
	public List<CampDocumentBean> getAllCampDocuments() {
		return adminRepository.getAllCampDocuments();
	}

	/**
	 * get all documents for camps
	 *
	 * @return the list of documents for camps
	 */
	public List<DocumentBean> getDocumentsForCamps() {
		return adminRepository.getAllDocumentsWith(T_DOCUMENT.DOCTYPE.eq(EnumDocument.camp));
	}

	/**
	 * get a map of camp beans
	 *
	 * @return the map
	 */
	public Map<Integer, CampBean> getCampMap() {
		return getAllCamps().stream().collect(Collectors.toMap(CampBean::getPk, Function.identity()));
	}

	/**
	 * get a map of document beans
	 *
	 * @return the map
	 */
	public Map<Integer, DocumentBean>  getDocumentsMap() {
		return getAllDocuments().stream().collect(Collectors.toMap(DocumentBean::getPk, Function.identity()));
	}

	/**
	 * upsert a camp document bean
	 *
	 * @param bean the bean
	 */
	public void upsertCampDocument(@Valid CampDocumentBean bean) {
		if (bean.getPk() == null) {
			adminRepository.insertCampDocument(bean.getFkCamp(), bean.getFkDocument());
		} else {
			adminRepository.updateCampDocument(bean.getPk(), bean.getFkCamp(), bean.getFkDocument());
		}
	}

	/**
	 * delete the camp document combination
	 *
	 * @param id the ID of the combination
	 */
	public void deleteCampDocument(Integer id) {
		adminRepository.deleteCampDocument(id);
	}
}
