package de.zalando.aruha.nakadi.controller;

import de.zalando.aruha.nakadi.NakadiException;
import de.zalando.aruha.nakadi.domain.EventType;
import de.zalando.aruha.nakadi.problem.DuplicatedEventTypeNameProblem;
import de.zalando.aruha.nakadi.problem.ValidationProblem;
import de.zalando.aruha.nakadi.repository.DuplicatedEventTypeNameException;
import de.zalando.aruha.nakadi.repository.EventTypeRepository;
import de.zalando.aruha.nakadi.repository.NoSuchEventTypeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import org.zalando.problem.MoreStatus;
import org.zalando.problem.Problem;

import javax.validation.Valid;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.List;

import static org.springframework.http.ResponseEntity.status;

@RestController
@RequestMapping(value = "/event_types")
public class EventTypeController {

    final private EventTypeRepository repository;

    @Autowired
    public EventTypeController(EventTypeRepository repository) {
        this.repository = repository;
    }

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<?> list() {
        List<EventType> eventTypes = repository.list();

        return status(HttpStatus.OK).body(eventTypes);
    }

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<?> createEventType(@Valid @RequestBody final EventType eventType, final Errors errors) throws Exception {
        if (errors.hasErrors()) {
            final Problem problem = new ValidationProblem(errors);

            return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);
        } else {
            return persist(eventType);
        }
    }

    @RequestMapping(value = "/{name}", method = RequestMethod.PUT)
    public ResponseEntity<?> update(
            @PathVariable("name") final String name,
            @RequestBody @Valid final EventType eventType,
            final Errors errors) {
        if (errors.hasErrors()) {
            final Problem problem = new ValidationProblem(errors);

            return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);
        }

        try {
            final EventType existingEventType = repository.findByName(name);

            validateName(name, eventType, errors);
            validateSchema(eventType, existingEventType, errors);

            if (!errors.hasErrors()) {
                repository.update(eventType);

                return status(HttpStatus.OK).build();
            } else {
                final Problem problem = new ValidationProblem(errors);

                return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);
            }
        } catch (NoSuchEventTypeException e) {
            final Problem problem = Problem.
                    builder().
                    withType(URI.create("https://httpstatuses.com/404")).
                    withTitle("Resource not found").
                    withDetail("No such event type named \"" + eventType.getName() + "\"").
                    withStatus(Response.Status.NOT_FOUND).
                    build();

            return status(HttpStatus.NOT_FOUND).body(problem);
        } catch (NakadiException e) {
            final Problem problem = Problem.
                    builder().
                    withType(URI.create("https://httpstatuses.com/422")).
                    withTitle("Could not update event type").
                    withDetail(e.getMessage()).
                    withStatus(MoreStatus.UNPROCESSABLE_ENTITY).
                    build();

            return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);
        }
    }

    private void validateName(final String name, final EventType eventType, final Errors errors) {
        if (!eventType.getName().equals(name)) {
            errors.rejectValue("name",
                    "The submitted event type name \"" +
                            eventType.getName() +
                            "\" should match the parameter name \"" +
                            name + "\"");
        }
    }

    private void validateSchema(final EventType eventType, final EventType existingEventType, final Errors errors) {
        if (!existingEventType.getEventTypeSchema().equals(eventType.getEventTypeSchema())) {
            errors.rejectValue("schema", "The schema you've just submitted is different from the one in our system.");
        }
    }

    private ResponseEntity<?> persist(final EventType eventType) {
        try {
            repository.saveEventType(eventType);

            return status(HttpStatus.CREATED).build();
        } catch (DuplicatedEventTypeNameException e) {
            final Problem problem = new DuplicatedEventTypeNameProblem(e.getName());

            return status(HttpStatus.CONFLICT).body(problem);
        } catch (NakadiException e) {
            return status(500).body(e.getMessage()); // TODO build proper Problem
        }
    }
}

@@ -829,16 +829,61 @@
 .Valid;%0A
+import javax.validation.constraints.NotNull;%0A
 import j
@@ -1720,135 +1720,41 @@
     
-final Problem problem = new ValidationProblem(errors);%0A%0A            return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem
+return unprocessableEntity(errors
 );%0A 
@@ -2126,135 +2126,41 @@
     
-final Problem problem = new ValidationProblem(errors);%0A%0A            return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem
+return unprocessableEntity(errors
 );%0A 
@@ -2256,25 +2256,24 @@
 Name(name);%0A
-%0A
             
@@ -2455,33 +2455,32 @@
 ate(eventType);%0A
-%0A
                 
@@ -2558,1042 +2558,387 @@
     
-final Problem problem = new ValidationProblem(errors);%0A%0A                return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);%0A            %7D%0A        %7D catch (NoSuchEventTypeException e) %7B%0A            final Problem problem = Problem.%0A                    builder().%0A                    withType(URI.create(%22https://httpstatuses.com/404%22)).%0A                    withTitle(%22Resource not found%22).%0A                    withDetail(%22No such event type named %5C%22%22 + eventType.getName() + %22%5C%22%22).%0A                    withStatus(Response.Status.NOT_FOUND).%0A                    build();%0A%0A            return status(HttpStatus.NOT_FOUND).body(problem);%0A        %7D catch (NakadiException e) %7B%0A            final Problem problem = Problem.%0A                    builder().%0A                    withType(URI.create(%22https://httpstatuses.com/422%22)).%0A                    withTitle(%22Could not update event type%22).%0A                    withDetail(e.getMessage()).%0A                    withStatus(MoreStatus.UNPROCESSABLE_ENTITY).%0A                    build();%0A
+return unprocessableEntity(errors);%0A            %7D%0A        %7D catch (NoSuchEventTypeException e) %7B%0A            final Problem problem = Problem.valueOf(Response.Status.NOT_FOUND);%0A            return status(HttpStatus.NOT_FOUND).body(problem);%0A        %7D catch (NakadiException e) %7B%0A            final Problem problem = Problem.valueOf(MoreStatus.UNPROCESSABLE_ENTITY, e.getMessage());
 %0A   
@@ -3925,17 +3925,16 @@
 tType);%0A
-%0A
         
@@ -4318,11 +4318,218 @@
  %7D%0A    %7D
+%0A%0A    private ResponseEntity%3C?%3E unprocessableEntity(Errors errors) %7B%0A        final Problem problem = new ValidationProblem(errors);%0A        return status(HttpStatus.UNPROCESSABLE_ENTITY).body(problem);%0A    %7D
 %0A%7D%0A

ARUHA-50 remove duplications