package kr.co.tobby48.medihand.controllers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import kr.co.tobby48.medihand.models.EManagementStatus;
import kr.co.tobby48.medihand.models.Management;
import kr.co.tobby48.medihand.models.User;
import kr.co.tobby48.medihand.payload.request.management.AddManagementRequest;
import kr.co.tobby48.medihand.payload.request.management.UpdateManagementRequest;
import kr.co.tobby48.medihand.payload.response.management.ManagementCommonResponse;
import kr.co.tobby48.medihand.payload.response.management.ManagementResponse;
import kr.co.tobby48.medihand.repository.ManagementRepository;
import kr.co.tobby48.medihand.repository.UserRepository;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/management")
public class ManagementController {
	@Autowired
	private ManagementRepository managementRepository;

//	@Autowired
//	private PatientRepository patientRepository;
	
	@Autowired
	private UserRepository userRepository;
	
	@GetMapping("/{userId}")
	public List<ManagementResponse> getManagementByUsers(@PathVariable Long userId) {
		List<ManagementResponse> responses = new ArrayList<ManagementResponse>();
		
		DateUtils.truncate(new Date(),Calendar.DAY_OF_MONTH);
		
		List<Management> managements = managementRepository.findByUser_Id(userId);

//		Map<Integer, List<Management>> grouped = managements.stream().sorted(Comparator.comparing(Management::getStatus)).collect(Collectors.groupingBy(Management::getStatus));
		Map<EManagementStatus, List<Management>> grouped = managements.stream()
				.filter(s-> DateUtils.isSameDay(new Date(), s.getStartdt()))
				.sorted(Comparator.comparing(Management::getStartdt)).collect(Collectors.groupingBy(Management::getStatus));
		int index = 1;
		for (EManagementStatus element : EManagementStatus.values()){
			//	status가 포함되어 있지 않으면 빈 리스트
			if(!grouped.containsKey(element)) {
				ManagementResponse res = new ManagementResponse(index-1, element);
				res.setTasks(new ArrayList<>());
				responses.add(res);
			}
			else {
				ManagementResponse res = new ManagementResponse(index-1, element);
				List<ManagementCommonResponse> tasks = new ArrayList<ManagementCommonResponse>();
				for(Management m : grouped.get(element)) {
//					title, String description, String status
					ManagementCommonResponse n = new ManagementCommonResponse(m, element);
					tasks.add(n);
				}
//				appointment인 경우에만 정렬
				if(index == 1) tasks.sort(Comparator.naturalOrder());
//				tasks.sort(Comparator.naturalOrder());
				res.setTasks(tasks);
				responses.add(res);
			}
			index++;
		}
		
		
//		for(Entry<Integer, List<Management>> entry : grouped.entrySet()) {
//			String status = ManagementStatus.values()[entry.getKey()-1].name();
//			ManagementResponse res = new ManagementResponse(status);
//			List<ManagementCommonResponse> tasks = new ArrayList<ManagementCommonResponse>();
//			for(Management m : entry.getValue()) {
////				title, String description, String status
//				ManagementCommonResponse n = new ManagementCommonResponse(m, status, new ArrayList<>());
//				tasks.add(n);
//			}
//			res.setTasks(tasks);
//			responses.add(res);
//		}
		return responses;
	}
	
	@GetMapping("/{userId}/{status}")
	public List<Management> getManagementByUsersAndStatus(@PathVariable Long userId, @PathVariable EManagementStatus status) {
		List<Management> managements = managementRepository.findByUser_Id(userId);
		List<Management> responses = managements.stream().filter(f -> f.getStatus().equals(status)).collect(Collectors.toList());
		return responses;
	}
	
	@PostMapping("/")
	public ResponseEntity<?> save(@Valid @RequestBody AddManagementRequest request) {
		User user = userRepository.findById(request.getUser_id()).orElseGet(User::new);
//		Patient patient = patientRepository.findById(request.getPatient_id()).orElseGet(Patient::new);
		
		Management management = new Management(request, user);
		managementRepository.save(management);

//		return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
		return ResponseEntity.ok(management);
	}
	
	
	@PutMapping("/")
	public ResponseEntity<?> update(@Valid @RequestBody UpdateManagementRequest request) {
		Management management = managementRepository.findById(request.getId()).orElseGet(Management::new);
//		Patient patient = patient = patientRepository.findById(request.getPatient_id()).orElseGet(Patient::new);
		
		management = request.update(management);
//		ObjectMapper o = new ObjectMapper();
//		try {
//			System.out.println(o.writeValueAsString(management));
//		} catch (JsonProcessingException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		managementRepository.save(management);
//		
		return ResponseEntity.ok(management);
	}
	
	@DeleteMapping("/{id}")
	public ResponseEntity<?> delete(@PathVariable Long id) {
//		Management management = managementRepository.findById(id).orElseGet(Management::new);
//		System.out.println(id);
//		managementRepository.delete(management);
		managementRepository.deleteById(id);
		return ResponseEntity.ok(id);
	}
	
	
	@GetMapping("/{userId}/all")
	public List<Management> getAll(@PathVariable Long userId) {
		
		List<Management> managements = managementRepository.findByUser_Id(userId);

//		Map<Integer, List<Management>> grouped = managements.stream().sorted(Comparator.comparing(Management::getStatus)).collect(Collectors.groupingBy(Management::getStatus));
		List<Management> grouped = managements.stream().sorted(Comparator.comparing(Management::getStartdt)).collect(Collectors.toList());
		
		return grouped;
	}
	
	@SuppressWarnings({ "deprecation" })
	@GetMapping("/{userId}/statistic")
	public List<Collection<Integer>> getStatistic(@PathVariable Long userId) {
		Map<Long, Integer> newPatients = new HashMap<Long, Integer>();
		Map<Long, Integer> oldPatients = new HashMap<Long, Integer>();
		
		Map<Integer, Integer> newPatientsMonth = new TreeMap<Integer, Integer>();
		Map<Integer, Integer> oldPatientsMonth = new TreeMap<Integer, Integer>();
		for(int i=0; i<12; i++) {
			newPatientsMonth.put(i, 0); oldPatientsMonth.put(i, 0);
		}
		Date now = new Date();
		
		List<Management> managements = managementRepository.findByUser_Id(userId);
		for(Management m : managements) {
			//	같은 해만 계산
			if(m.getStartdt().getYear() != now.getYear()) continue;
			
			//	새 환자에 포함되어있으면 기존환자에 추가
			if(newPatients.containsKey(m.getPatient().getId())) {
				//	기존환자에도 있으면 +1
				if(oldPatients.containsKey(m.getPatient().getId())) oldPatients.put(m.getPatient().getId(), oldPatients.get(m.getPatient().getId()) + 1);
				//	없다면 1
				else oldPatients.put(m.getPatient().getId(), 1);

				//	통계계산
				oldPatientsMonth.put(m.getStartdt().getMonth(), oldPatientsMonth.get(m.getStartdt().getMonth()) + 1);
			}
			else {
				newPatients.put(m.getPatient().getId(), 1);
				
				//	통계계산
				newPatientsMonth.put(m.getStartdt().getMonth(), newPatientsMonth.get(m.getStartdt().getMonth()) + 1);
			}
			
		}
//		System.out.println(newPatientsMonth.values());
//		System.out.println(oldPatientsMonth.values());
		
		return Arrays.asList(newPatientsMonth.values(), oldPatientsMonth.values());
	}
}
