package com.yihu.wlyy.service.app.team;

import com.yihu.wlyy.entity.doctor.profile.Doctor;
import com.yihu.wlyy.entity.doctor.team.admin.AdminTeam;
import com.yihu.wlyy.entity.doctor.team.admin.AdminTeamMember;
import com.yihu.wlyy.entity.patient.Patient;
import com.yihu.wlyy.repository.doctor.DoctorAdminTeamDao;
import com.yihu.wlyy.repository.doctor.DoctorAdminTeamMemberDao;
import com.yihu.wlyy.repository.doctor.DoctorDao;
import com.yihu.wlyy.repository.doctor.DoctorTeamMemberDao;
import com.yihu.wlyy.service.BaseService;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 医生行政团队服务。
 *
 * @author Sand
 */
@Component
@Transactional
public class AdminTeamService extends BaseService {
    @Autowired
    DoctorDao doctorDao;

    @Autowired
    DoctorAdminTeamDao teamDao;

    @Autowired
    DoctorAdminTeamMemberDao memberDao;

    @Autowired
    DoctorTeamMemberDao signingTeamMemberDao;

    /**
     * 获取团队数量。
     *
     * @return
     */
    public long getTeamCount() {
        return teamDao.count();
    }

    /**
     * 创建团队。
     *
     * @param teamName
     * @param leaderCode
     * @param orgCode
     * @return
     */
    public AdminTeam createTeam(String teamName, String leaderCode, String orgCode) {
        AdminTeam team = new AdminTeam();
        team.setName(teamName);
        team.setLeaderCode(leaderCode);
        team.setOrgCode(orgCode);
        team.setAvailable(true);
        team.setCreateTime(new Date());

        saveTeam(team);

        return team;
    }

    /**
     * 获取团队信息。
     *
     * @param id
     */
    public AdminTeam getTeam(long id) {
        AdminTeam team = teamDao.findOne(id);
        return team;
    }

    public Map<String, Object> getPatientSigningTeam(String patientCode){
        Object result[] = (Object[]) teamDao.getPatientSigningTeam(patientCode);
        if (result == null) return null;

        Map<String, Object> team = new HashMap<>();
        team.put("teamId", result[0]);
        team.put("teamName", result[1]);
        team.put("doctorCode", result[2]);
        team.put("doctorName", result[3]);
        team.put("healthDoctorCode", result[4]);
        team.put("healthDoctorName", result[5]);

        return team;
    }

    /**
     * 更新团队名称。
     *
     * @param teamId
     * @param teamName
     * @return
     */
    public AdminTeam updateTeamName(long teamId, String teamName) {
        AdminTeam team = getTeam(teamId);
        if (team != null) {
            if (teamName != null) team.setName(teamName);

            saveTeam(team);
        }

        return team;
    }

    /**
     * 更新团队领导。
     *
     * @param teamId
     * @param doctorCode
     * @return
     */
    public AdminTeam updateTeamLeader(long teamId, String doctorCode) {
        AdminTeam team = getTeam(teamId);
        if (team != null) {
            if (doctorCode != null) team.setLeaderCode(doctorCode);

            saveTeam(team);
        }

        return team;
    }

    /**
     * 获取此医生所在的团队列表。
     *
     * @param doctorCode
     * @return
     */
    public List<AdminTeam> getDoctorTeams(String doctorCode) {
        return memberDao.findDoctorTeams(doctorCode);
    }

    /**
     * 添加成员。
     *
     * @param teamId
     * @param doctorCode
     */
    public void addMember(long teamId, String doctorCode) {
        if (!memberDao.isMemberExist(teamId, doctorCode)) {
            AdminTeamMember member = new AdminTeamMember();
            member.setTeamId(teamId);
            member.setDoctorCode(doctorCode);
            member.setJoinTime(new Date());
            saveMember(member);
        }
    }

    /**
     * 移除成员逻辑：
     * 1、判断团队内是否有三师签约关系，如果有不能删除。
     * 2、若没有三师签约关系，判断是否为专科医生，如果是，直接删除
     * 3、若不是，则判断健康管理师或全科医生是否有签约人，有的话提示先转移居民。
     *
     * @param teamId
     * @param doctorCode
     */
    public Pair<Integer, String> removeMember(long teamId, String doctorCode) {
        if(signingTeamMemberDao.isSanShiSigning(doctorCode)){
            return new ImmutablePair<>(403, "三师签约医生，不能删除");
        }

        Doctor doctor = doctorDao.findByCode(doctorCode);
        if (!doctor.isProfessionalDoctor()){
            if (doctor.isGeneralDoctor()){
                List<Doctor> doctorList = new ArrayList<>();
                doctorList.add(doctor);

                Integer count = getMemberSigningCount(teamId, doctorList).get(doctorCode);
                if (count != null || count > 0){
                    if (doctor.isGeneralDoctor()){
                        return new ImmutablePair<>(403, "全科医生有签约关系，不可删除");
                    } else if (doctor.isHealthDoctor()){
                        return new ImmutablePair<>(403, "健康管理师仍有签约居民，请先转移签约居民");
                    }
                }
            }
        }

        AdminTeamMember member = memberDao.findByTeamIdAndDoctorCodeOrderByDoctorCodeAsc(teamId, doctorCode);
        if (member != null) memberDao.delete(member);

        return new ImmutablePair<>(200, "OK");
    }

    public List<Doctor> getMembers(long teamId) {
        return memberDao.findAllMembers(teamId);
    }

    /**
     * 获取不在当前团队内的机构成员。
     *
     * @param orgCode
     * @param teamId
     * @param page
     * @param size
     * @return
     */
    public List<Doctor> getExcludedMembers(String orgCode, String doctorName, long teamId, int page, int size) {
        Pageable pageable = new PageRequest(page, size);
        if (StringUtils.isEmpty(doctorName)) {
            doctorName = "%";
        } else {
            doctorName = "%" + doctorName + "%";
        }

        Page<Doctor> doctors = memberDao.findTeamExcludedMembers(orgCode, doctorName, teamId, pageable);
        if (doctors == null) return null;

        return doctors.getContent();
    }

    /**
     * 团队内所有成员的签约人数。
     *
     * @param doctors
     * @return
     */
    public Map<String, Integer> getMemberSigningCount(long teamId, List<Doctor> doctors) {
        Map<String, Integer> counts = new HashMap<>();

        for (Doctor doctor : doctors) {
            if (doctor.isProfessionalDoctor()) continue;

            Integer signingCount;
            if (doctor.isHealthDoctor()) {
                signingCount = teamDao.getHealthDoctorSignCount(doctor.getCode(), teamId);
            } else {
                signingCount = teamDao.getDoctorSignCount(doctor.getCode(), teamId);
            }

            counts.put(doctor.getCode(), signingCount);
        }

        return counts;
    }

    /**
     * 团队内所有成员的签约患者列表。以健康管理师为中心，与全科医生为准的交集。
     *
     * @param teamId
     * @param healthDoctorCode
     * @param page
     * @param size
     * @return
     */
    public List<Patient> getMemberSigningPatients(long teamId, String healthDoctorCode, int page, int size) {
        Page<Patient> result = teamDao.getHealthDoctorSigningPatients(healthDoctorCode, teamId, new PageRequest(page, size));

        return result.getContent();
    }

    /**
     * 保存团队。
     *
     * @param team
     */
    private void saveTeam(AdminTeam team) {
        teamDao.save(team);
    }

    /**
     * 保存成员。
     *
     * @param member
     */
    private void saveMember(AdminTeamMember member) {
        memberDao.save(member);
    }
}
