package com.ffii.tbms.api.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.ffii.core.utils.CriteriaUtils;
import com.ffii.core.utils.MapUtils;
import com.ffii.core.utils.NumberUtils;
import com.ffii.core.utils.Params;
import com.ffii.core.utils.web.ServletRequestUtils;
import com.ffii.core.web.AbstractController;
import com.ffii.core.web.view.json.JsonView;
import com.ffii.tbms.api.service.AuthenticationService;
import com.ffii.tbms.api.service.CustomerApiService;
import com.ffii.tbms.api.service.OrderApiService;
import com.ffii.tbms.customer.service.CustomerService;
import com.ffii.tbms.file.FileRefType;
import com.ffii.tbms.file.service.FileService;
import com.ffii.tbms.log.LogUtils;
import com.ffii.tbms.order.Order;
import com.ffii.tbms.order.OrderItem;
import com.ffii.tbms.order.service.OrderItemService;
import com.ffii.tbms.order.service.OrderService;

import org.apache.commons.lang3.SerializationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping(value = "api/order/")
/**
 * OrderApiController
 */
public class OrderApiController extends AbstractController {

    @Autowired
    AuthenticationService authenticationService;

    @Autowired
    OrderApiService service;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    CustomerApiService customerApiService;

    @Autowired
    private FileService fileService;
     
    @RequestMapping(value = "save", method = { RequestMethod.GET, RequestMethod.POST })
    public String saveOrder(Model model, @RequestParam String deviceId, @RequestParam String token, HttpServletRequest request,
            @RequestParam(defaultValue = "-1") Integer id) {

        logger.info("saveOrder : "+id);
        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        Order instance;
        if (id > 0) {
            instance = service.find(id);
            logger.info("order found : "+id);
        } else {
            instance = new Order();
            instance.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
            logger.info("new order: "+NumberUtils.toInt(userData.get("sysGroupId"),0));
        }

        ServletRequestUtils.doBind(request, instance, null);
        id = service.saveOrUpdate(instance);
        logger.info("Order Save: "+instance.toString());

        model.addAttribute(Params.ID, id);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);

        return JsonView.NAME;
    }

    @RequestMapping(value = "list", method = { RequestMethod.GET, RequestMethod.POST })
    public String listOrder(Model model, @RequestParam String deviceId, @RequestParam String token,
            HttpServletRequest request) throws Exception {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        final Map<String, Object> args = new HashMap<String, Object>();

        CriteriaUtils.addInteger(request, args, Params.ID);
        CriteriaUtils.addStringLike(request, args, "searchStr");
        CriteriaUtils.addInteger(request, args, "custId");
        args.put("sysGroupId", userData.get("sysGroupId"));

        CriteriaUtils.addInteger(request, args, "start");
        CriteriaUtils.addInteger(request, args, "limit");
        
        logger.info("args : " + args);

        final List<Map<String, Object>> records = service.search(args);

        //logger.info("record : " + records);

        model.addAttribute(Params.AUTH, Boolean.TRUE);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);
        model.addAttribute(Params.RECORDS, records);

        return JsonView.NAME;
    }


    @RequestMapping(value = "combo", method = { RequestMethod.GET, RequestMethod.POST })
    public String OrderCombo(Model model, @RequestParam String deviceId, @RequestParam String token,
            HttpServletRequest request) throws ServletRequestBindingException {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        final Map<String, Object> args = new HashMap<String, Object>();
        CriteriaUtils.addInteger(request, args, Params.ID);
        CriteriaUtils.addInteger(request, args, "customerId");
        CriteriaUtils.addStringLike(request, args, "searchStr");

        if(args.containsKey("searchStr") && args.get("searchStr").toString().length()>=2){
            args.put("_searchStr", args.get("searchStr"));
            CriteriaUtils.addString(request, args, "searchStr");
            List<Map<String, Object>> records = service.comboSearch(args);
            model.addAttribute(Params.RECORDS, records);
        }else if(args.containsKey("id")){
            List<Map<String, Object>> records = service.comboSearch(args);
            if(records != null)
                model.addAttribute(Params.DATA, records.get(0));
            else
                model.addAttribute(Params.DATA, new HashMap<>());
        }else if(args.containsKey("customerId")){
            List<Map<String, Object>> records = service.comboSearch(NumberUtils.intValue(args.get("customerId")));
            if(records != null)
                model.addAttribute(Params.DATA, records.get(0));
            else
                model.addAttribute(Params.DATA, new HashMap<>());
        }else{
            model.addAttribute(Params.AUTH, Boolean.TRUE);
            model.addAttribute(Params.SUCCESS, Boolean.TRUE);
            model.addAttribute(Params.RECORDS, null);
            return JsonView.NAME;
        }

        model.addAttribute(Params.AUTH, Boolean.TRUE);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);
        return JsonView.NAME;
    }

    @RequestMapping(value = "detail", method = { RequestMethod.GET, RequestMethod.POST })
    public String loadDetail(Model model, @RequestParam String deviceId, @RequestParam String token,
            HttpServletRequest request) throws Exception {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        final Map<String, Object> args = new HashMap<>();

        CriteriaUtils.addInteger(request, args, Params.ID);

        final Map<String, Object> data = service.loadOrder(args);
        final List<Map<String, Object>> itemRecords = service.searchItems(args);

        model.addAttribute(Params.AUTH, Boolean.TRUE);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);
        model.addAttribute(Params.DATA, data);
        model.addAttribute("itemRecords", itemRecords);

        return JsonView.NAME;
    }

    
    @RequestMapping(value = "load", method = { RequestMethod.GET, RequestMethod.POST })
    public String loadForOrderEdit(Model model, @RequestParam String deviceId, @RequestParam String token,
            HttpServletRequest request) throws Exception {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        final Map<String, Object> args = new HashMap<>();

        CriteriaUtils.addInteger(request, args, Params.ID);

        final Map<String, Object> data = service.loadOrder(args);

        model.addAttribute("selectedOrderRef", null);
        if(data.get("ref") != null){
            List<Map<String, Object>> refOrder = service.comboSearch(MapUtils.toHashMap("sysGroupId", userData.get("sysGroupId"),"orderId", data.get("ref")));
            if(refOrder!=null && refOrder.size()>0){
                model.addAttribute("selectedOrderRef", refOrder.get(0));
            }
        }

        model.addAttribute("selectedCustomer", null);
        if(data.get("custId") != null){
            List<Map<String, Object>> cust = customerApiService.searchForCombo(MapUtils.toHashMap("id", data.get("custId")));
            if(cust!=null && cust.size()>0){
                model.addAttribute("selectedCustomer", cust.get(0));
            }
        }

        model.addAttribute(Params.AUTH, Boolean.TRUE);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);
        model.addAttribute(Params.DATA, data);

        return JsonView.NAME;
    }


    @RequestMapping(value = "get-current-ms.json", method = { RequestMethod.GET, RequestMethod.POST })
    public String getCurrentMS(Model model, @RequestParam String deviceId, @RequestParam String token, HttpServletRequest request, Integer orderId) {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        Order order = service.find(orderId);

        Map<String, Object> args = new HashMap<String, Object>();
        List<Map<String, Object>> records = new ArrayList<>();
        if (order != null && order.getFileId() != null && order.getFileId() > 0) {
            args.put("fileId", order.getFileId());
            args.put("refType", FileRefType.MEASUREMENT_SHEET);
            records = fileService.searchFiles(args);
        }
        model.addAttribute(Params.RECORDS, records);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);
        return JsonView.NAME;
    }

    @RequestMapping(value = "image-list-json", method = { RequestMethod.GET, RequestMethod.POST })
    public String getImageJson(Model model, @RequestParam String deviceId, @RequestParam String token, HttpServletRequest request, Integer orderId) {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        final Map<String, Object> args = new HashMap<String, Object>();
        args.put("refType", FileRefType.ORDER);
        args.put("refId", orderId);
        final List<Map<String, Object>> records = fileService.searchFiles(args);

        model.addAttribute(Params.AUTH, Boolean.TRUE);
        model.addAttribute(Params.RECORDS, records);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);

        return JsonView.NAME;
    }

    @RequestMapping(value = "item/save", method = { RequestMethod.GET, RequestMethod.POST })
    public String saveOrderItem(Model model, @RequestParam String deviceId, @RequestParam String token, HttpServletRequest request,
            @RequestParam(defaultValue = "-1") Integer id) throws ServletRequestBindingException, JsonProcessingException {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        OrderItem instance;
        OrderItem oldRecord;
        if (id > 0) {
            instance = orderItemService.find(id);
            logger.info("order Item found : "+id);
            orderItemService.compare(instance, request);
            oldRecord = SerializationUtils.clone(instance);
        } else {
            instance = new OrderItem();
            oldRecord = new OrderItem();
            instance.setSysGroupId(NumberUtils.toInt(userData.get("sysGroupId"),0));
            logger.info("new order Item");
        }

        ServletRequestUtils.doBind(request, instance, null);
        id = orderItemService.saveOrUpdate(instance);
        logger.info("Order Item Save: "+instance.toString());
        
        //save log
        if(oldRecord.getId() != null){
            orderItemService.log(LogUtils.ACTION_UPDATE, id, NumberUtils.intValue(userData.get("id")), instance, oldRecord);
        }else{
            orderItemService.log(LogUtils.ACTION_CREATE, id, NumberUtils.intValue(userData.get("id")), instance);
        }

        model.addAttribute(Params.ID, id);
        model.addAttribute(Params.SUCCESS, Boolean.TRUE);

        return JsonView.NAME;
    }

    
    @RequestMapping(value = "item/delete", method = { RequestMethod.GET, RequestMethod.POST })
    public String deleteOrderItem(Model model, @RequestParam String deviceId, @RequestParam String token, HttpServletRequest request,
            @RequestParam(defaultValue = "-1") Integer id) throws JsonProcessingException {

        Map<String, Object> userData = authenticationService.findUserByAccessToken(deviceId, token);
        if (userData == null) {
            model.addAllAttributes(authenticationService.getNoUserFoundMap());
            return JsonView.NAME;
        }

        boolean haveAuth = authenticationService.haveAuth(userData.get("id"),"ORDER_MAINTAIN");
        if (!haveAuth) {
            model.addAllAttributes(authenticationService.getNoAuthFoundMap());
            return JsonView.NAME;
        }

        OrderItem instance;
        if (id > 0) {
            instance = orderItemService.find(id);
            logger.info("order Item found (delete) : "+id);
            instance.setDeleted(true);
            id = orderItemService.saveOrUpdate(instance);
            orderItemService.log("Delete", id, NumberUtils.intValue(userData.get("id")), instance);

            model.addAttribute(Params.ID, id);
            model.addAttribute(Params.SUCCESS, Boolean.TRUE);

            return JsonView.NAME;
        } 
           
        model.addAttribute(Params.SUCCESS, Boolean.FALSE);
        return JsonView.NAME;
    }

}