package jp.kobe_u.cs27.newse.medicalcheck.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import jp.kobe_u.cs27.newse.medicalcheck.dto.PersonDto;
import jp.kobe_u.cs27.newse.medicalcheck.entity.Person;
import jp.kobe_u.cs27.newse.medicalcheck.exception.MedicalCheckException;
import jp.kobe_u.cs27.newse.medicalcheck.repository.PersonRepository;

/**
 * 受診者の情報を管理するサービスクラス．登録，1件検索，全件検索
 */
@Service
public class PersonManager {
    @Autowired
    PersonRepository persons;

    /**
     * 受診者を追加する
     * @param person 受診者
     * @return 追加された受診者
     */
    public Person addPerson(Person person) {
        Long number = person.getNumber();
        if (number != null && persons.findById(number).isPresent()) {
            throw new MedicalCheckException(MedicalCheckException.PERSON_ALREADY_EXISTS,
            "Person #" + number + " already exists");
        } else {
            return persons.save(person);
        }
    }

    /**
     * 受診者番号を指定して受診者を更新する 
     * @param number 受診者番号
     * @param person 受診者
     * @return 更新された受診者
     */
    public Person updatePerson(Long number, Person person) {
        //存在チェック
        if (persons.findById(number).isEmpty()) {
            throw new MedicalCheckException(
                MedicalCheckException.NO_SUCH_PERSON, 
                "No such person #" + number);
        } else {
            //受診番号をセットして，上書き
            person.setNumber(number);
            return persons.save(person);
        }
    }
    
    /**
     * 受診者番号を指定して，受診者情報（BMI, 肥満度含む）を取得する．
     * @param number 受診者番号
     * @return 受診者情報
     */
    public PersonDto getPerson(Long number) {
        Person p = persons.findById(number).orElseThrow(
            ()-> new MedicalCheckException(MedicalCheckException.NO_SUCH_PERSON,
            "No such person #" + number));

        return PersonDto.build(p);
    }

    /**
     * すべての受診者情報(BMI, 肥満度含む)を取得する．
     */
    public List<PersonDto> getAllPersons() {
        ArrayList<PersonDto> list = new ArrayList<PersonDto>();
        
        for (Person p : persons.findAll()) {
            list.add(PersonDto.build(p));
        }
        return list;
    }

    /**
     * 受診者番号を指定してデータを削除する
     * @param number 受診者番号
     */
    public void deletePerson(Long number) {
        Person p = persons.findById(number).orElseThrow(
            ()-> new MedicalCheckException(MedicalCheckException.NO_SUCH_PERSON,
            "No such person #" + number));
        persons.delete(p);
    }


    /**
     * 名前で検索する．
     */
    public List<PersonDto> searchPersonsByName(String name) {
        ArrayList<PersonDto> list = new ArrayList<PersonDto>();
        
        for (Person p : persons.findPersonByNameLike( "%" + name + "%")) {
            list.add(PersonDto.build(p));
        }
        return list;
    }

    /**
     * 体重で検索する．
     */
    public List<PersonDto> searchPersonsByWeight(double min, double max) {
        ArrayList<PersonDto> list = new ArrayList<PersonDto>();
        
        for (Person p : persons.findPersonByWeightBetween(min, max)) {
            list.add(PersonDto.build(p));
        }
        return list;
    }

    /**
     * 身長で検索する．
     */
    public List<PersonDto> searchPersonsByHeight(double min, double max) {
        ArrayList<PersonDto> list = new ArrayList<PersonDto>();
        
        for (Person p : persons.findPersonByHeightBetween(min, max)) {
            list.add(PersonDto.build(p));
        }
        return list;
    }

    /**
     * 生まれ月で検索する．
     */
    public List<PersonDto> searchPersonsByMonth(int month) {
        ArrayList<PersonDto> list = new ArrayList<PersonDto>();
        
        for (Person p : persons.findPersonByMonth(month)) {
            list.add(PersonDto.build(p));
        }
        return list;
    }

}