package com.progetto.VEBS.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.stereotype.Service;

import com.progetto.VEBS.mapper.AreaVerdeMapper;
import com.progetto.VEBS.model.dto.AreaBluDTO;
import com.progetto.VEBS.model.dto.AreaVerdeDTO;
import com.progetto.VEBS.model.entity.AreaBlu;
import com.progetto.VEBS.model.entity.AreaVerde;
import com.progetto.VEBS.model.entity.PoligonoAreaVerde;
import com.progetto.VEBS.model.repository.AreaVerdeRepository;
import com.progetto.VEBS.model.repository.PoligonoAreaVerdeRepository;

@Service
public class AreaVerdeService {

	@Autowired
	private AreaVerdeMapper mapper;

	@Autowired
	private AreaVerdeRepository areaVerdeRepository;

	@Autowired
	private PoligonoAreaVerdeRepository poligonoAreaVerdeRepository;

	public List<AreaVerdeDTO> getAllAreeVerdi() {
		return areaVerdeRepository.findAll().stream().map(mapper::toDTO).collect(Collectors.toList());
	}

	public AreaVerdeDTO getAreaVerdeById(Integer id) {
		return areaVerdeRepository.findById(id).map(mapper::toDTO).orElse(null);
	}

	public void saveAreaVerde(AreaVerdeDTO areaverde) {
		areaVerdeRepository.save(mapper.toEntity(areaverde));
	}

	public void deleteAreaVerdeById(Integer id) throws ResourceNotFoundException {
		areaVerdeRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Record non trovato"));
		areaVerdeRepository.deleteById(id);
	}

	public void updateAreaVerde(AreaVerdeDTO areaverdeDTO) throws ResourceNotFoundException {
		AreaVerde areaverde = areaVerdeRepository.findById(areaverdeDTO.getId())
				.orElseThrow(() -> new ResourceNotFoundException("Record non trovato"));

		WKTReader reader = new WKTReader();
		Geometry geom;
		try {
			geom = reader.read(areaverdeDTO.getGeometria());
			areaverde.setGeometria(geom);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		areaverde.setId(areaverdeDTO.getId());
		areaverde.setNome(areaverdeDTO.getNome());
		areaverde.setDensita_alberi(areaverdeDTO.getDensita_alberi());
		areaverde.setArea(areaverdeDTO.getArea());
		areaverde.setComune(areaverdeDTO.getComune());
		areaverde.setUbicazione(areaverdeDTO.getUbicazione());
		areaverde.setPoligono_area_verde(areaverdeDTO.getPoligono_area_verde());

		areaVerdeRepository.saveAndFlush(areaverde);
	}

	public void updateAreaVerdeAndCreatePolAreaVerde(AreaVerdeDTO areaverdeDTO) throws ResourceNotFoundException {

		// creo il record nella tabella dei poligoni aree verdi
		PoligonoAreaVerde poligono_area_verde = new PoligonoAreaVerde();

		WKTReader reader = new WKTReader();
		Geometry geom;
		try {
			geom = reader.read(areaverdeDTO.getGeometria());
			poligono_area_verde.setGeometria(geom);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		poligono_area_verde.setComune(areaverdeDTO.getComune());
		poligono_area_verde.setNome(areaverdeDTO.getNome());
		poligono_area_verde.setDensita_alberi(areaverdeDTO.getDensita_alberi());
		poligono_area_verde.setArea(areaverdeDTO.getArea());

		poligonoAreaVerdeRepository.saveAndFlush(poligono_area_verde);

		// aggiorno i campi dell'area verde
		AreaVerde areaverde = new AreaVerde();

		areaverde.setId(areaverdeDTO.getId());
		areaverde.setNome(areaverdeDTO.getNome());
		areaverde.setDensita_alberi(areaverdeDTO.getDensita_alberi());
		areaverde.setArea(areaverdeDTO.getArea());
		areaverde.setComune(areaverdeDTO.getComune());
		areaverde.setUbicazione(areaverdeDTO.getUbicazione());
		areaverde.setPoligono_area_verde(poligono_area_verde);
		try {
			geom = reader.read(areaverdeDTO.getGeometria());
			areaverde.setGeometria(geom);
		} catch (ParseException e) {
			e.printStackTrace();
		}

		areaVerdeRepository.saveAndFlush(areaverde);
	}

	public Map<String, Object> getFieldsAreeVerdi() {
		Map<String, Object> fields = new HashMap();
		for (Field field : AreaVerde.class.getDeclaredFields()) {
			fields.put(field.getName(), null);
		}
		return fields;
	}

	public void updateAreaVerdeAndUpdatePolAreaVerde(AreaVerdeDTO areaverdeDTO, Integer id) {
		
		// faccio update del record nella tabella dei poligoni aree verdi
		PoligonoAreaVerde poligono_area_verde = new PoligonoAreaVerde();

		WKTReader reader = new WKTReader();
		Geometry geom;
		try {
			geom = reader.read(areaverdeDTO.getGeometria());
			poligono_area_verde.setGeometria(geom);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		poligono_area_verde.setId(id);
		poligono_area_verde.setComune(areaverdeDTO.getComune());
		poligono_area_verde.setNome(areaverdeDTO.getNome());
		poligono_area_verde.setDensita_alberi(areaverdeDTO.getDensita_alberi());
		poligono_area_verde.setArea(areaverdeDTO.getArea());

		poligonoAreaVerdeRepository.saveAndFlush(poligono_area_verde);

		// aggiorno i campi dell'area verde
		AreaVerde areaverde = new AreaVerde();

		areaverde.setId(areaverdeDTO.getId());
		areaverde.setNome(areaverdeDTO.getNome());
		areaverde.setDensita_alberi(areaverdeDTO.getDensita_alberi());
		areaverde.setArea(areaverdeDTO.getArea());
		areaverde.setComune(areaverdeDTO.getComune());
		areaverde.setUbicazione(areaverdeDTO.getUbicazione());
		areaverde.setPoligono_area_verde(poligono_area_verde);
		try {
			geom = reader.read(areaverdeDTO.getGeometria());
			areaverde.setGeometria(geom);
		} catch (ParseException e) {
			e.printStackTrace();
		}

		areaVerdeRepository.saveAndFlush(areaverde);

	}

	public List<Map<String,Object>> getAllIdNomeFields() {
		
		List<Object[]> records = areaVerdeRepository.getIdNomeFromAreeVerdi();
		List<Map<String,Object>> result = new ArrayList<>();
		
		for(Object[] record : records) {
			Map<String,Object> map = new HashMap();
			map.put("id", record[0]);
			map.put("nome", (record[1] == null)? "senza nome" : record[1]);
			result.add(map);
		}
		
		return result;
	}

	public List<AreaVerdeDTO> getAllAreeVerdiFromComune(String comune) {
		return areaVerdeRepository.findByComune(comune);
	}
}
