package pl.lgawin.paypal.ipn.api;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Strings;

import org.apache.commons.codec.Charsets;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.stream.Collectors;

import javax.inject.Inject;
import pl.lgawin.paypal.ipn.data.NotificationRepository;
import pl.lgawin.paypal.ipn.dto.HttpRequestDetails;
import pl.lgawin.paypal.ipn.utils.SchwartzianTransformItem;

@RestController
public class MainController {

    private static final String PAY_KEY_PARAM = "pay_key";

    private final NotificationRepository notificationRepository;

    @Inject
    public MainController(NotificationRepository notificationRepository) {
        this.notificationRepository = checkNotNull(notificationRepository);
    }

    @RequestMapping("/")
    String home() {
        return "Hello, this is Simple Ipn Handler.";
    }

    @RequestMapping(path = "/ipn", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseStatus(HttpStatus.OK)
    void handleNotification(@RequestBody String body, @RequestHeader HttpHeaders headers) {
        notificationRepository.log(new HttpRequestDetails(DateTime.now(DateTimeZone.getDefault()), headers, body));
    }

    @RequestMapping(path = "/notifications", method = RequestMethod.GET)
    NotificationsResponse notificationsByPayKey(@RequestParam(required = false, name = PAY_KEY_PARAM) String payKey) {
        Collection<HttpRequestDetails> notifications = notificationRepository.all();
        if (!Strings.isNullOrEmpty(payKey)) notifications = notifications.stream()
                .map(entry -> new SchwartzianTransformItem<>(entry,
                        request -> URLEncodedUtils.parse(request.getBody(), Charsets.UTF_8).stream()
                                .map(pair -> new SchwartzianTransformItem<>(pair, NameValuePair::getName))
                                .filter(name -> PAY_KEY_PARAM.equals(name.mapped()))
                                .findAny()
                                .map(SchwartzianTransformItem::original)
                                .map(NameValuePair::getValue)))
                .filter(value -> value.mapped().isPresent())
                .filter(value -> payKey.equalsIgnoreCase(value.mapped().get()))
                .map(SchwartzianTransformItem::original)
                .collect(Collectors.toList());
        return new NotificationsResponse(notifications);
    }

}

@@ -465,16 +465,77 @@
 iaType;%0A
+import org.springframework.web.bind.annotation.PathVariable;%0A
 import o
@@ -965,37 +965,8 @@
 r;%0A%0A
-import java.util.Collection;%0A
 impo
@@ -996,16 +996,48 @@
 lectors;
+%0Aimport java.util.stream.Stream;
 %0A%0Aimport
@@ -2162,16 +2162,8 @@
 ions
-ByPayKey
 (@Re
@@ -2242,19 +2242,287 @@
     
-Collection%3C
+if (!Strings.isNullOrEmpty(payKey)) %7B%0A            return notificationsByPayKey(payKey);%0A        %7D%0A        return new NotificationsResponse(notificationRepository.all());%0A    %7D%0A%0A    @RequestMapping(path = %22/notifications/byPayKey/%7BpayKey%7D/latest%22, method = RequestMethod.GET)%0A    
 Http
@@ -2535,19 +2535,24 @@
 tDetails
-%3E n
+ latestN
 otificat
@@ -2559,114 +2559,604 @@
 ions
- = notificationRepository.a
+ByPayKey(@PathVariable String payKey) %7B%0A        return notificationsByPayKayAsStream(payKey).findFirst().orElse(nu
 ll
-(
 );%0A    
+%7D%0A%0A
     
-if (!Strings.isNullOrEmpty(payKey)) notifications = notifications
+@RequestMapping(path = %22/notifications/byPayKey/%7BpayKey%7D%22, method = RequestMethod.GET)%0A    NotificationsResponse notificationsByPayKey(@PathVariable String payKey) %7B%0A        return new NotificationsResponse(notificationsByPayKayAsStream(payKey).collect(Collectors.toList()));%0A    %7D%0A%0A    private Stream%3CHttpRequestDetails%3E notificationsByPayKayAsStream(@RequestParam(required = false, name = PAY_KEY_PARAM) String payKey) %7B%0A        return notificationRepository.all()
 .str
@@ -3190,16 +3190,40 @@
 entry -%3E
+%0A                       
  new Sch
@@ -3253,16 +3253,24 @@
 (entry,%0A
+        
         
@@ -3390,24 +3390,32 @@
             
+     
+   
 .map(pair -%3E
@@ -3501,32 +3501,40 @@
                 
+        
 .filter(name -%3E 
@@ -3602,16 +3602,24 @@
         
+    
+    
 .findAny
@@ -3621,16 +3621,24 @@
 ndAny()%0A
+        
         
@@ -3694,32 +3694,40 @@
 Item::original)%0A
+        
                 
@@ -3975,118 +3975,15 @@
 nal)
-%0A                .collect(Collectors.toList());%0A        return new NotificationsResponse(notifications)
 ;%0A    %7D%0A
 %0A%7D%0A
@@ -3979,11 +3979,10 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A

Handle different /notifications filtered by pay_key