/*
 *  Copyright (c) 2025 John Ahlroos / Devsoap
 *
 *  Creative Commons Attribution-NoDerivatives 4.0 International Public License
 *
 *  By exercising the Licensed Rights (defined below), You accept and agree
 *  to be bound by the terms and conditions of this Creative Commons
 *  Attribution-NoDerivatives 4.0 International Public License ("Public
 *  License"). To the extent this Public License may be interpreted as a
 *  contract, You are granted the Licensed Rights in consideration of Your
 *  acceptance of these terms and conditions, and the Licensor grants You
 *  such rights in consideration of benefits the Licensor receives from
 *  making the Licensed Material available under these terms and
 *  conditions.
 *
 *  Refer to LICENSE file or https://creativecommons.org/licenses/by-nd/4.0 for full license.
 *
 */

package com.devsoap.tincheck.routes;

import com.devsoap.tincheck.tin.TinGenerator;
import com.devsoap.tincheck.routes.requests.TinGenerateRequest;
import com.devsoap.tincheck.routes.requests.TinValidateRequest;
import com.devsoap.tincheck.routes.responses.GenerationResult;
import com.devsoap.tincheck.services.TinCheckService;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.MutableHttpResponse;
import io.micronaut.http.annotation.*;
import io.micronaut.http.annotation.Error;
import io.micronaut.http.server.util.HttpHostResolver;
import io.micronaut.views.View;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.validation.Valid;
import java.time.LocalDate;
import java.util.Map;

@Slf4j
@Controller
@RequiredArgsConstructor
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_HTML)
public class Routes {

    private final TinCheckService service;
    private final HttpHostResolver hostResolver;

    @Post("/validate")
    @View("validation-result")
    public HttpResponse<Map<String,String>> validate(@Valid TinValidateRequest request, HttpRequest<?> httpRequest) {
        var result = service.validateRateLimited(request.country(), request.value());
        return responseWithCorsHeaders(httpRequest, HttpResponse.ok(switch (result.result()) {
            case "valid" -> Map.of("class", result.result(), "text", "TIN is valid");
            case "invalid" -> Map.of("class", result.result(), "text", "TIN is invalid");
            default -> Map.of("class", result.result(), "text", "Unknown error");
        }));
    }

    @Get
    @View("index")
    public Map<String,Object> index() {
        return Map.of(
                "countries", service.getCountryMap(),
                "defaultCountry", service.getDefaultCountry().getCountryCode(),
                "defaultValue", service.generateRateLimited(service.getDefaultCountry().getCountryCode(),
                        LocalDate.of(1983, 6,29), TinGenerator.Gender.MALE).value()
        );
    }

    @Post("/generate")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public HttpResponse<GenerationResult> generate(@Valid TinGenerateRequest request, HttpRequest<?> httpRequest){
        return responseWithCorsHeaders(httpRequest, HttpResponse.ok(
                service.generateRateLimited(request.country(), request.dateOfBirth(), request.gender())));
    }

    @Error(exception = IllegalArgumentException.class)
    public HttpResponse<?> handleInvalidParameters(IllegalArgumentException e) {
        log.error("Invalid parameters for request: {}", e.getMessage());
        return HttpResponse.badRequest(e.getMessage()).contentType(MediaType.TEXT_PLAIN);
    }

    @Error(exception = RequestNotPermitted.class)
    public HttpResponse<?> handleRateLimit(RequestNotPermitted e) {
        log.info("Rate limit for request triggered: {}", e.getMessage());
        return HttpResponse.unauthorized().body(Map.of("error",
                "Free validations consumed. Please buy subscription for more validations."));
    }

    private <T> HttpResponse<T> responseWithCorsHeaders(HttpRequest<?> httpRequest, MutableHttpResponse<T> response) {
        return response
                .header( "Access-Control-Allow-Origin", hostResolver.resolve(httpRequest))
                .header("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
    }
}