// Path: src/main/java/org/learning/by/example/reactive/microservices/handlers/ApiHandler.java
// public class ApiHandler {
// 
//   private static final String ADDRESS = "address";
//   private static final String EMPTY_STRING = "";
// 
//   private final ErrorHandler errorHandler;
// 
//   private final GeoLocationService geoLocationService;
//   private final SunriseSunsetService sunriseSunsetService;
// 
//   public ApiHandler(final GeoLocationService geoLocationService, final SunriseSunsetService sunriseSunsetService,
//                     final ErrorHandler errorHandler) {
//     this.errorHandler = errorHandler;
//     this.geoLocationService = geoLocationService;
//     this.sunriseSunsetService = sunriseSunsetService;
//   }
// 
//   public Mono<ServerResponse> postLocation(final ServerRequest request) {
//     return request.bodyToMono(LocationRequest.class)
//         .map(LocationRequest::getAddress)
//         .onErrorResume(throwable -> Mono.just(EMPTY_STRING))
//         .transform(this::buildResponse)
//         .onErrorResume(errorHandler::throwableError);
//   }
// 
//   public Mono<ServerResponse> getLocation(final ServerRequest request) {
//     return Mono.just(request.pathVariable(ADDRESS))
//         .transform(this::buildResponse)
//         .onErrorResume(errorHandler::throwableError);
//   }
// 
//   Mono<ServerResponse> buildResponse(final Mono<String> address) {
//     return address
//         .transform(geoLocationService::fromAddress)
//         .zipWhen(this::sunriseSunset, LocationResponse::new)
//         .transform(this::serverResponse);
//   }
// 
//   private Mono<SunriseSunset> sunriseSunset(GeographicCoordinates geographicCoordinates) {
//     return Mono.just(geographicCoordinates).transform(sunriseSunsetService::fromGeographicCoordinates);
//   }
// 
//   Mono<ServerResponse> serverResponse(Mono<LocationResponse> locationResponseMono) {
//     return locationResponseMono.flatMap(locationResponse ->
//         ServerResponse.ok().body(Mono.just(locationResponse), LocationResponse.class));
//   }
// }
// 
// Path: src/main/java/org/learning/by/example/reactive/microservices/handlers/ErrorHandler.java
// public class ErrorHandler {
// 
//     private static final String NOT_FOUND = "not found";
//     private static final String ERROR_RAISED = "error raised";
//     private static final Logger logger = LoggerFactory.getLogger(ErrorHandler.class);
// 
//     public Mono<ServerResponse> notFound(final ServerRequest request) {
//         return Mono.just(new PathNotFoundException(NOT_FOUND)).transform(this::getResponse);
//     }
// 
//     Mono<ServerResponse> throwableError(final Throwable error) {
//         logger.error(ERROR_RAISED, error);
//         return Mono.just(error).transform(this::getResponse);
//     }
// 
//     <T extends Throwable> Mono<ServerResponse> getResponse(final Mono<T> monoError) {
//         return monoError.transform(ThrowableTranslator::translate)
//                 .flatMap(translation -> ServerResponse
//                         .status(translation.getHttpStatus())
//                         .body(Mono.just(new ErrorResponse(translation.getMessage())), ErrorResponse.class));
//     }
// }
// 
// Path: src/main/java/org/learning/by/example/reactive/microservices/routers/MainRouter.java
// public class MainRouter {
// 
//     public static RouterFunction<?> doRoute(final ApiHandler handler, final ErrorHandler errorHandler) {
//         return ApiRouter
//                 .doRoute(handler, errorHandler)
//                 .andOther(StaticRouter.doRoute());
//     }
// }


import org.learning.by.example.reactive.microservices.handlers.ApiHandler;
import org.learning.by.example.reactive.microservices.handlers.ErrorHandler;
import org.learning.by.example.reactive.microservices.routers.MainRouter;
import org.learning.by.example.reactive.microservices.services.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.function.server.RouterFunction;
package org.learning.by.example.reactive.microservices.application;


@Configuration
@EnableWebFlux
class ApplicationConfig {

    @Bean
    ApiHandler apiHandler(final GeoLocationService geoLocationService, final SunriseSunsetService sunriseSunsetService,
                          final ErrorHandler errorHandler) {
        return new ApiHandler(geoLocationService, sunriseSunsetService, errorHandler);
    }

    @Bean
    GeoLocationService locationService(@Value("${GeoLocationServiceImpl.endPoint}") final String endPoint) {
        return new GeoLocationServiceImpl(endPoint);
    }

    @Bean
// Path: src/main/java/org/learning/by/example/reactive/microservices/handlers/ApiHandler.java
// public class ApiHandler {
// 
//   private static final String ADDRESS = "address";
//   private static final String EMPTY_STRING = "";
// 
//   private final ErrorHandler errorHandler;
// 
//   private final GeoLocationService geoLocationService;
//   private final SunriseSunsetService sunriseSunsetService;
// 
//   public ApiHandler(final GeoLocationService geoLocationService, final SunriseSunsetService sunriseSunsetService,
//                     final ErrorHandler errorHandler) {
//     this.errorHandler = errorHandler;
//     this.geoLocationService = geoLocationService;
//     this.sunriseSunsetService = sunriseSunsetService;
//   }
// 
//   public Mono<ServerResponse> postLocation(final ServerRequest request) {
//     return request.bodyToMono(LocationRequest.class)
//         .map(LocationRequest::getAddress)
//         .onErrorResume(throwable -> Mono.just(EMPTY_STRING))
//         .transform(this::buildResponse)
//         .onErrorResume(errorHandler::throwableError);
//   }
// 
//   public Mono<ServerResponse> getLocation(final ServerRequest request) {
//     return Mono.just(request.pathVariable(ADDRESS))
//         .transform(this::buildResponse)
//         .onErrorResume(errorHandler::throwableError);
//   }
// 
//   Mono<ServerResponse> buildResponse(final Mono<String> address) {
//     return address
//         .transform(geoLocationService::fromAddress)
//         .zipWhen(this::sunriseSunset, LocationResponse::new)
//         .transform(this::serverResponse);
//   }
// 
//   private Mono<SunriseSunset> sunriseSunset(GeographicCoordinates geographicCoordinates) {
//     return Mono.just(geographicCoordinates).transform(sunriseSunsetService::fromGeographicCoordinates);
//   }
// 
//   Mono<ServerResponse> serverResponse(Mono<LocationResponse> locationResponseMono) {
//     return locationResponseMono.flatMap(locationResponse ->
//         ServerResponse.ok().body(Mono.just(locationResponse), LocationResponse.class));
//   }
// }
// 
// Path: src/main/java/org/learning/by/example/reactive/microservices/handlers/ErrorHandler.java
// public class ErrorHandler {
// 
//     private static final String NOT_FOUND = "not found";
//     private static final String ERROR_RAISED = "error raised";
//     private static final Logger logger = LoggerFactory.getLogger(ErrorHandler.class);
// 
//     public Mono<ServerResponse> notFound(final ServerRequest request) {
//         return Mono.just(new PathNotFoundException(NOT_FOUND)).transform(this::getResponse);
//     }
// 
//     Mono<ServerResponse> throwableError(final Throwable error) {
//         logger.error(ERROR_RAISED, error);
//         return Mono.just(error).transform(this::getResponse);
//     }
// 
//     <T extends Throwable> Mono<ServerResponse> getResponse(final Mono<T> monoError) {
//         return monoError.transform(ThrowableTranslator::translate)
//                 .flatMap(translation -> ServerResponse
//                         .status(translation.getHttpStatus())
//                         .body(Mono.just(new ErrorResponse(translation.getMessage())), ErrorResponse.class));
//     }
// }
// 
// Path: src/main/java/org/learning/by/example/reactive/microservices/routers/MainRouter.java
// public class MainRouter {
// 
//     public static RouterFunction<?> doRoute(final ApiHandler handler, final ErrorHandler errorHandler) {
//         return ApiRouter
//                 .doRoute(handler, errorHandler)
//                 .andOther(StaticRouter.doRoute());
//     }
// }


// Path: src/main/java/org/learning/by/example/reactive/microservices/application/ApplicationConfig.java
import org.learning.by.example.reactive.microservices.handlers.ApiHandler;
import org.learning.by.example.reactive.microservices.handlers.ErrorHandler;
import org.learning.by.example.reactive.microservices.routers.MainRouter;
import org.learning.by.example.reactive.microservices.services.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.function.server.RouterFunction;

package org.learning.by.example.reactive.microservices.application;


@Configuration
@EnableWebFlux
class ApplicationConfig {

    @Bean
    ApiHandler apiHandler(final GeoLocationService geoLocationService, final SunriseSunsetService sunriseSunsetService,
                          final ErrorHandler errorHandler) {
        return new ApiHandler(geoLocationService, sunriseSunsetService, errorHandler);
    }

    @Bean
    GeoLocationService locationService(@Value("${GeoLocationServiceImpl.endPoint}") final String endPoint) {
        return new GeoLocationServiceImpl(endPoint);
    }

    @Bean
    SunriseSunsetService sunriseSunsetService(@Value("${SunriseSunsetServiceImpl.endPoint}") final String endPoint) {