/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 org.apache.causeway.viewer.graphql.viewer.test.e2e.special;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.approvaltests.Approvals;
import org.approvaltests.reporters.DiffReporter;
import org.approvaltests.reporters.UseReporter;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.ActiveProfiles;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import org.apache.causeway.viewer.graphql.viewer.test.e2e.Abstract_IntegTest;

//NOT USING @Transactional since we are running server within same transaction otherwise
@Order(60)
@ActiveProfiles("test")
public class Staff_2_IntegTest extends Abstract_IntegTest {

    @Test
    @UseReporter(DiffReporter.class)
    void find_staff_member_by_name_and_download_photo() throws Exception {

        String response = submit();
        Approvals.verify(response, jsonOptions());

        var objectMapper = new ObjectMapper();
        var jsonNodeRoot = objectMapper.readTree(response);

        var gridUrl = jsonNodeRoot
                .at("/data/rich/university_dept_Staff/findStaffMemberByName/invoke/results/_meta/grid")
                .asText();

        assertThat(gridUrl).matches("///graphql/object/university.dept.StaffMember:(\\d+)/_meta/grid");
        var gridHttpResponse = submitReturningString(gridUrl);

        assertThat(gridHttpResponse.statusCode()).isEqualTo(200);
        var gridChars = gridHttpResponse.body();
        assertThat(gridChars).isNotEmpty();

        var photoBytesUrl = jsonNodeRoot
                .at("/data/rich/university_dept_Staff/findStaffMemberByName/invoke/results/photo/get/bytes")
                .asText();

        assertThat(photoBytesUrl).matches("///graphql/object/university.dept.StaffMember:(\\d+)/photo/blobBytes");
        var photoBytesResponse = submitReturningBytes(photoBytesUrl);
        assertThat(photoBytesResponse.statusCode()).isEqualTo(200);
        var photoBytes = photoBytesResponse.body();
        assertThat(photoBytes).isNotEmpty();

        var iconBytesUrl = jsonNodeRoot
                .at("/data/rich/university_dept_Staff/findStaffMemberByName/invoke/results/_meta/icon")
                .asText();

        assertThat(iconBytesUrl).matches("///graphql/object/university.dept.StaffMember:(\\d+)/_meta/icon");
        var iconBytesResponse = submitReturningBytes(iconBytesUrl);
        assertThat(iconBytesResponse.statusCode()).isEqualTo(200);
        var iconBytes = iconBytesResponse.body();
        assertThat(iconBytes).isNotEmpty();
    }

    private HttpResponse<byte[]> submitReturningBytes(String url) throws IOException, InterruptedException {
        return submitReturningResponseHandledBy(url, HttpResponse.BodyHandlers.ofByteArray());
    }

    private HttpResponse<String> submitReturningString(String url) throws IOException, InterruptedException {
        return submitReturningResponseHandledBy(url, HttpResponse.BodyHandlers.ofString());
    }

    private <T> HttpResponse<T> submitReturningResponseHandledBy(String url, HttpResponse.BodyHandler<T> responseBodyHandler) throws IOException, InterruptedException {
        var urlSuffix = url.substring(3); // strip off the '///' prefix
        var uri = URI.create(String.format("http://0.0.0.0:%d/%s", port, urlSuffix));

        HttpRequest httpRequest = HttpRequest.newBuilder().
                uri(uri).
                GET().
                build();

        HttpClient httpClient = HttpClient.newHttpClient();
        return httpClient.send(httpRequest, responseBodyHandler);
    }

}
