package com.jasamedika.medifirst2000.controller;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.servlet.http.HttpServletRequest;

import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.jasamedika.medifirst2000.base.vo.BaseMasterVO;
import com.jasamedika.medifirst2000.base.vo.BaseModelVO;
import com.jasamedika.medifirst2000.base.vo.BaseTransactionVO;
import com.jasamedika.medifirst2000.controller.base.LocaleController;
import com.jasamedika.medifirst2000.service.ModelService;
import com.jasamedika.medifirst2000.util.JsonUtil;
import com.jasamedika.medifirst2000.util.rest.RestUtil;
import com.jasamedika.medifirst2000.vo.AntrianPasienRegistrasiVO;

@RestController
@RequestMapping("/service")
public class GenericServiceController extends LocaleController<AntrianPasienRegistrasiVO> {

	@Autowired
	private ModelService<?> modelService;
	private static final String CONTENT_TYPE = "Content-Type";

	@SuppressWarnings("rawtypes")
	public static List<Field> GetFields(Class data) {
		List<Field> items = new ArrayList<Field>();
		Class parent = data.getSuperclass();
		Class tmpClass = null;
		if (BaseModelVO.class.isAssignableFrom(data.getClass())) {
			tmpClass = BaseTransactionVO.class;
		} else if (BaseTransactionVO.class.isAssignableFrom(data.getClass())) {
			tmpClass = BaseMasterVO.class;
		}

		if ((data == tmpClass)) {
			for (Field field : data.getDeclaredFields()) {
				items.add(field);
			}
			return items;
		}

		if (parent != null) {
			for (Field field : GetFields(data.getSuperclass())) {
				items.add(field);
			}
		}

		for (Field field : data.getDeclaredFields()) {
			items.add(field);
		}
		return items;
	}

	@RequestMapping(value = "/get-setting/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<String> getData(@RequestParam(value = "prefix", required = false) String prefix) {

		return RestUtil.getJsonResponse(GetSettingDataFixed(prefix), HttpStatus.CREATED, mapHeaderMessage);
	}

	@RequestMapping(value = "/list-generic/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<List<Map<String, Object>>> listGeneric(
			@RequestParam(value = "view", required = false) String entity,
			@RequestParam(value = "select", required = false) String field,
			@RequestParam(value = "take", required = false) Integer take,
			@RequestParam(value = "skip", required = false) Integer skip,
			@RequestParam(value = "page", required = false) Integer page,
			@RequestParam(value = "pageSize", required = false) Integer pageSize,
			@RequestParam(value = "filter[logic]", required = false) String logic,
			@RequestParam(value = "filter[filters][0][value]", required = false) String value,
			@RequestParam(value = "filter[filters][0][field]", required = false) String fieldS,
			@RequestParam(value = "filter[filters][0][operator]", required = false) String operator,
			@RequestParam(value = "filter[filters][0][ignoreCase]", required = false) String ignorecase,
			@RequestParam(value = "criteria", required = false) String criteria,
			@RequestParam(value = "values", required = false) String values, HttpServletRequest request)
			throws SecurityException, ClassNotFoundException, JSONException, UnsupportedEncodingException {

		String data = request.getQueryString();
		data = URLDecoder.decode(data, "UTF-8");
		String[] arrQueries = data.split("&");
		for (String query : arrQueries) {
			if (query.indexOf("filter[filters][0][filter][field]") >= 0) {
				if (criteria == null)
					criteria = query.replace("filter[filters][0][filter][field]=", "");
				else
					criteria += "," + query.replace("filter[filters][0][filter][field]=", "");

			} else if (query.indexOf("filter[filters][0][filter][value]") >= 0) {
				if (values == null)
					values = query.replace("filter[filters][0][filter][value]=", "");
				else
					values += "," + query.replace("filter[filters][0][filter][value]=", "");
			}
		}

		if (field.equals("*")) {
			field = "";

			for (Field fieldItem : GetFields(Class.forName("com.jasamedika.medifirst2000.entities." + entity))) {
				{
					String name = fieldItem.getName();
					if (name.equals("serialVersionsUID"))
						continue;
					Boolean valid = false;
					for (java.lang.annotation.Annotation annotation : fieldItem.getDeclaredAnnotations()) {
						if (annotation instanceof JoinColumn) {
							valid = true;
						} else if (annotation instanceof Column) {
							Column column = (Column) annotation;
							if (column.name().endsWith("Fk"))
								if (fieldItem.getName().endsWith("Id") == false)
									valid = true;
						} else if (annotation instanceof OneToMany) {

							valid = true;
						}

					}
					if (valid == false)
						if (field.equals(""))
							field += fieldItem.getName();
						else
							field += "," + fieldItem.getName();
				}
			}
		} else if (field.equals("**")) {
			field = "*";
		}

		// for dateformat using [date]
		List<Map<String, Object>> modelGenericVO = modelService.getAllData(entity, field, take, skip, page, pageSize,
				logic, value, fieldS, operator, ignorecase, criteria, values);
		HttpHeaders headers = new HttpHeaders();
		headers.set(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
		try {
			return new ResponseEntity<List<Map<String, Object>>>(JsonUtil.ToMaps(modelGenericVO), headers,
					HttpStatus.OK);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
		}

		return null;
	}

}
