package at.dru.ratemonitor.service.impl;

import at.dru.ratemonitor.data.ConversionRate;
import at.dru.ratemonitor.service.IHtmlParser;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

@Component
public class DefaultHtmlParser implements IHtmlParser {

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMAN);
    private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).withLocale(Locale.GERMAN);

    private static final String URL = "https://www.llb.li/de/private/anlegen/direktanlagen/devisen-und-edelmetalle/devisenkurse?iframe=1";

    @Value("${application.timeOut}")
    private int timeOut;

    @Value("${application.userAgent}")
    private String userAgent;

    @Nonnull
    @Override
    public List<ConversionRate> getConversionRates() {
        try {
            return loadRatesFromURL();
        } catch (IOException e) {
            throw new IllegalStateException("Cannot parse rates from url.", e);
        }
    }

    @Nonnull
    private List<ConversionRate> loadRatesFromURL() throws IOException {
        Document doc = Jsoup.connect(URL)
                .timeout(timeOut)
                .userAgent(userAgent)
                .get();

        String changedDatePart = Optional.ofNullable(doc.select("body > div > div > p:nth-child(1)"))
                .map(Elements::text)
                .map(text -> text.replace("Datum: ", "").trim())
                .orElseThrow(() -> new IllegalStateException("Cannot select changed date"));

        String changedTimePart = Optional.ofNullable(doc.select("body > div > div > p:nth-child(2)"))
                .map(Elements::text)
                .map(text -> text.replace("Zeit: ", "").trim())
                .orElseThrow(() -> new IllegalStateException("Cannot select changed time"));

        String changedDate = changedDatePart + " " + changedTimePart;
        LocalDateTime parsedDate = LocalDate.parse(changedDatePart, DATE_FORMAT).atTime(LocalTime.parse(changedTimePart, TIME_FORMAT));

        String country = Optional.ofNullable(doc.select("body > div > div > table > tbody > tr:nth-child(8) > td:nth-child(1)"))
                .map(Elements::text)
                .orElseThrow(() -> new IllegalStateException("Cannot select country"));

        double buyRate = Optional.ofNullable(doc.select("body > div > div > table > tbody > tr:nth-child(8) > td:nth-child(3)"))
                .map(Elements::text)
                .map(Double::valueOf)
                .orElseThrow(() -> new IllegalStateException("Cannot select buy rate"));

        double sellRate = Optional.ofNullable(doc.select("body > div > div > table > tbody > tr:nth-child(8) > td:nth-child(4)"))
                .map(Elements::text)
                .map(Double::valueOf)
                .orElseThrow(() -> new IllegalStateException("Cannot select sell rate"));

        ConversionRate conversionRate = new ConversionRate();
        conversionRate.setFromCurrency("CHF");
        conversionRate.setCountry(country);
        conversionRate.setToCurrency("EUR");
        conversionRate.setBuyRate(buyRate);
        conversionRate.setSellRate(sellRate);
        conversionRate.setChangedDate(changedDate);
        conversionRate.setParsedDate(parsedDate);

        return Collections.singletonList(conversionRate);
    }

}

@@ -186,16 +186,48 @@
 cument;%0A
+import org.jsoup.nodes.Element;%0A
 import o
@@ -359,16 +359,56 @@
 mponent;
+%0Aimport org.springframework.util.Assert;
 %0A%0Aimport
@@ -1350,24 +1350,90 @@
 userAgent;%0A%0A
+    @Value(%22$%7Bapplication.country%7D%22)%0A    private String country;%0A%0A
     @Nonnull
@@ -2721,30 +2721,31 @@
         
-String
+Element
  country
  = Optio
@@ -2736,39 +2736,26 @@
  country
- = Optional.ofNullable(
+Element = 
 doc.sele
@@ -2799,40 +2799,108 @@
 %3E tr
-:nth-child(8) %3E td:nth-child(1)%22
+%22)%0A                .stream()%0A                .filter(e -%3E country.equalsIgnoreCase(e.child(0).text()
 ))%0A 
@@ -2915,34 +2915,26 @@
        .
-map(Elements::text
+findFirst(
 )%0A      
@@ -3028,126 +3028,159 @@
     
-double buyRate = Optional.ofNullable(doc.select(%22body %3E div %3E div %3E table %3E tbody %3E tr:nth-child(8) %3E td:nth-
+Assert.isTrue(countryElement.childrenSize() == 4, %22Expected 4 children elements%22);%0A%0A        double buyRate = Optional.ofNullable(countryElement.
 child(
-3)%22
+2
 ))%0A 
@@ -3198,33 +3198,32 @@
     .map(Element
-s
 ::text)%0A        
@@ -3392,89 +3392,30 @@
 ble(
-doc.select(%22body %3E div %3E div %3E table %3E tbody %3E tr:nth-child(8) %3E td:nth-
+countryElement.
 child(
-4)%22
+3
 ))%0A 
@@ -3433,33 +3433,32 @@
     .map(Element
-s
 ::text)%0A        

fix parsing