package controllers.html;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import controllers.BaseController;
import controllers.api.HtmlRepresentation;
import org.joda.time.DateTime;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
import play.mvc.BodyParser;
import play.mvc.Result;
import uk.gov.openregister.JsonObjectMapper;
import uk.gov.openregister.config.ApplicationConf;
import uk.gov.openregister.domain.Record;
import uk.gov.openregister.linking.Curie;
import uk.gov.openregister.linking.CurieResolver;
import uk.gov.openregister.store.DatabaseConflictException;
import uk.gov.openregister.store.DatabaseException;
import uk.gov.openregister.validation.ValidationError;
import uk.gov.openregister.validation.Validator;

import java.util.*;
import java.util.stream.Collectors;

public class UI extends BaseController {

    public Result index() {
        long count = store.count();
        String lastUpdatedUI = "";
        try {
            CurieResolver curieResolver = new CurieResolver(ApplicationConf.getRegisterServiceTemplateUrl());
            String rrUrl = curieResolver.resolve(new Curie("register", register.name())) + "?_representation=json";

            final WSResponse wsResponse = WS.client().url(rrUrl).execute().get(30000L);
            final String lastUpdatedStr = wsResponse.asJson().get("last-updated").textValue();
            final DateTime lastUpdated = DateTime.parse(lastUpdatedStr);
            lastUpdatedUI = lastUpdated.toString("dd MMM yyyy");
        } catch (Exception e) {
            //ignore
        }

        return ok(views.html.index.render(register, count, lastUpdatedUI));
    }

    public Result renderNewEntryForm() {
        return ok(views.html.newEntry.render(register, Collections.emptyMap(), Collections.emptyMap()));
    }

    @BodyParser.Of(BodyParser.FormUrlEncoded.class)
    public Result create() {
        Map<String, String[]> requestParams = request.body().asFormUrlEncoded();

        Record record = createRecordFromQueryParams(requestParams);

        List<ValidationError> validationErrors = new Validator(Collections.singletonList(register.name()), register.fieldNames()).validate(record);
        if (validationErrors.isEmpty()) {
            try {
                store.save(record);
                return redirect("/hash/" + record.getHash());
            } catch (DatabaseException e) {
                return ok(views.html.newEntry.render(register, convertToMapOfListValues(requestParams), Collections.singletonMap("globalError", e.getMessage())));
            }
        }
        Map<String, String> errors = validationErrors.stream().collect(Collectors.toMap(error -> error.key, error -> error.message));

        return ok(views.html.newEntry.render(register, convertToMapOfListValues(requestParams), errors));
    }

    @SuppressWarnings("unchecked")
    public Result renderUpdateEntryForm(String hash) {
        Record record = store.findByHash(hash).get();

        Map params = JsonObjectMapper.convert(record.getEntry(), Map.class);

        return ok(views.html.updateEntry.render(register,
                        convertToMapOfListValues(params),
                        Collections.emptyMap(),
                        hash)
        );
    }

    @BodyParser.Of(BodyParser.FormUrlEncoded.class)
    public Result update(String hash) {
        Map<String, String[]> requestParams = request.body().asFormUrlEncoded();

        Record record = createRecordFromQueryParams(requestParams);

        List<ValidationError> validationErrors = new Validator(Collections.singletonList(register.name()), register.fieldNames()).validate(record);
        if (validationErrors.isEmpty()) {
            try {
                register.store().update(hash, record);
                return redirect("/hash/" + record.getHash());
            } catch (DatabaseConflictException e) {
                return HtmlRepresentation.instance.toResponse(409, e.getMessage(), register.friendlyName());
            }
        }
        Map<String, String> errors = validationErrors.stream().collect(Collectors.toMap(error -> error.key, error -> error.message));
        return ok(views.html.updateEntry.render(register,
                convertToMapOfListValues(requestParams),
                errors,
                hash));
    }

    private Map<String, List<String>> convertToMapOfListValues(Map<String, ?> requestParams) {
        Map<String, List<String>> stringListHashMap = new HashMap<>();
        for (String key : requestParams.keySet()) {
            if (requestParams.get(key) instanceof String[]) {
                stringListHashMap.put(key, Arrays.asList((String[]) requestParams.get(key)));
            } else if (requestParams.get(key) instanceof List) {
                stringListHashMap.put(key, (List) requestParams.get(key));
            } else {
                stringListHashMap.put(key, Arrays.asList((String) requestParams.get(key)));
            }
        }
        return stringListHashMap;
    }

    private Record createRecordFromQueryParams(Map<String, String[]> formParameters) {
        try {
            Map<String, Object> jsonMap = new HashMap<>();
            formParameters.keySet().stream().filter(register.fieldNames()::contains).forEach(key -> {
                if (register.name().equals("register") && key.equals("fields")) {
                    jsonMap.put(key, formParameters.get(key));
                } else {
                    jsonMap.put(key, formParameters.get(key)[0]);
                }
            });

            return new Record(new ObjectMapper().writeValueAsString(jsonMap));
        } catch (JsonProcessingException e) {
            throw new RuntimeException("TODO: json parsing exception, we need to address this when TODO above is done");
        }
    }
}


@@ -244,64 +244,8 @@
 me;%0A
-import play.libs.ws.WS;%0Aimport play.libs.ws.WSResponse;%0A
 impo
@@ -368,164 +368,21 @@
 ter.
-config.ApplicationConf;%0Aimport uk.gov.openregister.domain.Record;%0Aimport uk.gov.openregister.linking.Curie;%0Aimport uk.gov.openregister.linking.CurieResolver
+domain.Record
 ;%0Aim
@@ -617,9 +617,142 @@
 til.
-*
+Arrays;%0Aimport java.util.Collections;%0Aimport java.util.HashMap;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.Optional
 ;%0Aim
@@ -900,22 +900,34 @@
         
-String
+Optional%3CDateTime%3E
  lastUpd
@@ -934,140 +934,51 @@
 ated
-UI
  = 
-%22%22;%0A        try %7B%0A            CurieResolver curieResolver = new CurieResolver(ApplicationConf.getRegisterServiceTemplateUrl
+store.search(%22%22, 0, 1, Optional.empty
 ())
-;
 %0A   
@@ -990,322 +990,77 @@
     
-String rrUrl = curieResolver.resolve(new Curie(%22register%22, register.n
+    .stre
 am
-e
 ()
-)) + %22?_representation=json%22;%0A%0A            final WSResponse wsResponse = WS.client().url(rrUrl).execute().get(30000L);%0A            final String lastUpdatedStr = wsResponse.asJson().get(%22last-u
+.findFirst().map(Record::getLastU
 pdated
-%22).textValue();%0A            final DateTime
+);%0A        String
  las
@@ -1071,26 +1071,13 @@
 ated
+UI
  = 
-DateTime.parse(
 last
@@ -1087,13 +1087,8 @@
 ated
-Str);
 %0A   
@@ -1100,35 +1100,37 @@
     
-lastUpdatedUI = lastUpdated
+    .map(datetime -%3E datetime
 .toS
@@ -1149,17 +1149,17 @@
 M yyyy%22)
-;
+)
 %0A       
@@ -1163,62 +1163,28 @@
     
-%7D catch (Exception e) %7B%0A            //ignore%0A        %7D
+        .orElse(%22%22);
 %0A%0A  

make "last updated" less confusing