package net.waltzstudio.montecarlo.service;

import static net.waltzstudio.base.framework.util.SyntaxSugar.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.seasar.framework.beans.util.Beans;
import org.seasar.struts.util.RequestUtil;
import net.waltzstudio.montecarlo.dao.account.AccountDao;
import net.waltzstudio.montecarlo.dao.label.LabelDao;
import net.waltzstudio.montecarlo.dao.project.ProjectDao;
import net.waltzstudio.montecarlo.dao.ticket.TicketDao;
import net.waltzstudio.montecarlo.dao.ticketLabel.TicketLabelDao;
import net.waltzstudio.montecarlo.dao.ticketUnread.TicketUnreadDao;
import net.waltzstudio.montecarlo.dto.SessionInfoDto;
import net.waltzstudio.montecarlo.dto.api.AccountDto;
import net.waltzstudio.montecarlo.dto.api.LabelDto;
import net.waltzstudio.montecarlo.dto.api.ProjectDto;
import net.waltzstudio.montecarlo.dto.api.StatusDto;
import net.waltzstudio.montecarlo.dto.api.TicketDto;
import net.waltzstudio.montecarlo.entity.account.Account;
import net.waltzstudio.montecarlo.entity.label.Label;
import net.waltzstudio.montecarlo.entity.project.Project;
import net.waltzstudio.montecarlo.entity.ticket.Ticket;
import net.waltzstudio.montecarlo.entity.ticketLabel.TicketLabel;
import net.waltzstudio.montecarlo.entity.ticketUnread.TicketUnread;

/**
 * API Service
 */
public class ApiService {
	/** セッション情報 */
	@Resource
	protected SessionInfoDto sessionInfoDto;

	/** チケットDao */
	@Resource
	protected TicketDao ticketDao;
	/** ラベルDao */
	@Resource
	protected LabelDao labelDao;
	/** チケット・ラベル紐付けDao */
	@Resource
	protected TicketLabelDao ticketLabelDao;
	/** チケット未読Dao */
	@Resource
	protected TicketUnreadDao ticketUnreadDao;
	/** プロジェクトDao */
	@Resource
	protected ProjectDao projectDao;
	/** アカウントDao */
	@Resource
	protected AccountDao accountDao;

	public List<TicketDto> getTickets(Long projectId, Long labelId, boolean inbox) {
		List<TicketDto> dtos = new ArrayList<TicketDto>();
		Long accountId = sessionInfoDto.id;
		Map<Long, ProjectDto> projectMap = getProjectMap(accountId);
		Map<Long, AccountDto> accountMap = getAccountMap();
		Map<Long, List<LabelDto>> ticketLabelMap = getTicketLabelMap(accountId);
		Set<Long> ticketUnreadSet = getTicketUnreadSet(accountId);

		List<Ticket> tickets = ticketDao.findTrayTickets(accountId, projectId, labelId, inbox);
		for (Ticket ticket : tickets) {
			TicketDto dto = Beans.createAndCopy(TicketDto.class, ticket).excludes("status").execute();

			// プロジェクト
			if (projectMap.containsKey(ticket.projectId)) {
				dto.project = projectMap.get(ticket.projectId);
			}

			// 登録者
			if (accountMap.containsKey(ticket.registerId)) {
				dto.register = accountMap.get(ticket.registerId);
			}

			// 担当者
			if (accountMap.containsKey(ticket.assignedId)) {
				dto.assigned = accountMap.get(ticket.assignedId);
			}

			// ステータス
			dto.status = new StatusDto();
			dto.status.label = ticket.status.getLabel();
			dto.status.state = ticket.status.getState();
			dto.status.value = ticket.status.getValue();

			// ラベル
			if (ticketLabelMap.containsKey(ticket.id)) {
				dto.labels = ticketLabelMap.get(ticket.id);
			}

			// 未読
			if (ticketUnreadSet.contains(ticket.id)) {
				dto.isUnread = true;
			}

			// URL
			if (dto.project == null) {
				dto.url = S(RequestUtil.getRequest().getContextPath(), "/ticket/", ticket.id);
			} else {
				dto.url = S(RequestUtil.getRequest().getContextPath(), "/", dto.project.code, "/ticket/", ticket.id);
			}

			dtos.add(dto);
		}

		return dtos;
	}

	/**
	 * プロジェクトMap取得
	 *
	 * @param accountId アカウントID
	 * @return プロジェクトMap
	 */
	protected Map<Long, ProjectDto> getProjectMap(Long accountId) {
		Map<Long, ProjectDto> projectMap = new HashMap<Long, ProjectDto>();
		List<Project> projects = projectDao.findByAccountId(accountId);
		for (Project project : projects) {
			ProjectDto dto = Beans.createAndCopy(ProjectDto.class, project).execute();
			projectMap.put(dto.id, dto);
		}
		return projectMap;
	}

	/**
	 * アカウントMap取得
	 *
	 * @return アカウントMap
	 */
	protected Map<Long, AccountDto> getAccountMap() {
		Map<Long, AccountDto> accountMap = new HashMap<Long, AccountDto>();
		List<Account> accounts = accountDao.findAll();
		for (Account account : accounts) {
			AccountDto dto = Beans.createAndCopy(AccountDto.class, account).execute();
			accountMap.put(dto.id, dto);
		}
		return accountMap;
	}

	/**
	 * チケットラベルMap取得
	 *
	 * @param accountId アカウントID
	 * @return チケットラベルMap
	 */
	protected Map<Long, List<LabelDto>> getTicketLabelMap(Long accountId) {
		Map<Long, LabelDto> labelMap = new HashMap<Long, LabelDto>();
		Map<Long, List<LabelDto>> ticketLabelMap = new HashMap<Long, List<LabelDto>>();
		List<Label> labels = labelDao.findByAccountId(accountId);
		List<TicketLabel> ticketLabels = ticketLabelDao.findByAccountId(accountId);
		for (Label label : labels) {
			LabelDto dto = Beans.createAndCopy(LabelDto.class, label).execute();
			labelMap.put(dto.id, dto);
		}
		for (TicketLabel ticketLabel : ticketLabels) {
			if (!labelMap.containsKey(ticketLabel.labelId)) {
				continue;
			}
			LabelDto l = labelMap.get(ticketLabel.labelId);
			if (!ticketLabelMap.containsKey(ticketLabel.ticketId)) {
				ticketLabelMap.put(ticketLabel.ticketId, new ArrayList<LabelDto>());
			}
			ticketLabelMap.get(ticketLabel.ticketId).add(l);
		}
		return ticketLabelMap;
	}

	/**
	 * チケット未読Set取得
	 *
	 * @param accountId アカウントID
	 * @return チケット未読Set
	 */
	protected Set<Long> getTicketUnreadSet(Long accountId) {
		Set<Long> ticketUnreadSet = new HashSet<Long>();
		List<TicketUnread> ticketUnreads = ticketUnreadDao.findByAccountId(accountId);
		for (TicketUnread ticketUnread : ticketUnreads) {
			if (!ticketUnreadSet.contains(ticketUnread.ticketId)) {
				ticketUnreadSet.add(ticketUnread.ticketId);
			}
		}
		return ticketUnreadSet;
	}

}
