/*
 * Copyright (C) 2018-2020 Authlete, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the
 * License.
 */
package com.authlete.jaxrs.server.api;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.UUID;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import com.authlete.common.api.AuthleteApiFactory;
import com.authlete.jaxrs.BaseResourceEndpoint;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;


@Path("/api/fapi/{endpoint: .*}")
public class FapiResourceEndpoint extends BaseResourceEndpoint
{

    /**
     * JSON generator.
     */
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    // date parser
    SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");

    private static Logger logger = Logger.getLogger(FapiResourceEndpoint.class.getName());

    @GET
    public Response get(
            @HeaderParam(HttpHeaders.AUTHORIZATION) String authorization,
            @HeaderParam("x-fapi-financial-id") @DefaultValue("") String financialId,
            @HeaderParam("x-fapi-interaction-id") @DefaultValue("") String interactionId,
            @HeaderParam("x-fapi-auth-date") @DefaultValue("") String authDate,
            @HeaderParam("x-fapi-customer-ip-address") @DefaultValue("") String customerIpAddress,
            @Context HttpServletRequest request)
    {
        // Extract an access token from the Authorization header (note we don't pass in the query parameter)
        String token = extractAccessToken(authorization, null);

        return process(token, financialId, interactionId, authDate, customerIpAddress, extractClientCertificate(request));
    }


    private Response process(String accessToken, String financialId, String incomingInteractionId, String authDate, String customerIpAddress, String clientCertificate)
    {
        // Validate the access token. Because this endpoint does not require
        // any scopes, here we use the simplest variant of validateAccessToken()
        // methods which does not take 'requiredScopes' argument. See the JavaDoc
        // of BaseResourceEndpoint (authlete-java-jaxrs) for details.
        //
        // validateAccessToken() throws a WebApplicationException when the given
        // access token is invalid. The response contained in the exception
        // complies with RFC 6750, so you don't have to build the content of
        // WWW-Authenticate header in the error response by yourself.
        //
        // If you want to get information about the access token (e.g. the subject
        // of the user and the scopes associated with the access token), use
        // the object returned from validateAccessToken() method. It is an
        // instance of AccessTokenInfo class. If you want to get information
        // even in the case where validateAccessToken() throws an exception,
        // call AuthleteApi.introspect(IntrospectionRequest) directly.
        validateAccessToken(AuthleteApiFactory.getDefaultApi(), accessToken, null, null, clientCertificate);

        // The access token presented by the client application is valid.

        try
        {
            // log the financial ID
            if (financialId != null && !financialId.isEmpty())
            {
                logger.info("(Legacy) FAPI Financial ID: " + financialId);
            }

            String outgoingInteractionId = getInteractionId(incomingInteractionId);

            // log the interaction ID
            logger.info("FAPI Interaction ID: " + outgoingInteractionId);

            // try parsing the date header if it exists
            if (authDate != null && !authDate.isEmpty())
            {
                // this will throw an exception if the format is wrong
                format.parse(authDate);

                logger.info("Auth date: " + authDate);
            }

            if (customerIpAddress != null && !customerIpAddress.isEmpty())
            {
                logger.info("IP Address: " + customerIpAddress);
            }

            String json = GSON.toJson(new JsonObject());

            return Response.ok(json)
                    .header("x-fapi-interaction-id", outgoingInteractionId)
                    .build();
        }
        catch (IllegalArgumentException | ParseException e)
        {
            logger.severe(e.getMessage());
            return Response.status(Status.BAD_REQUEST).build();
        }
    }


    // Get the value for the x-fapi-interaction-id header to return
    private String getInteractionId(String interactionId)
    {
        if (interactionId != null && !interactionId.isEmpty())
        {
            // make sure the interaction ID is a UUID; this throws an IllegalArgumentException if it fails
            UUID.fromString(interactionId);

            return interactionId;

        }
        else
        {
            // return a new random UUID if we didn't get one in
            return UUID.randomUUID().toString();
        }
    }
}