/*
 * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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
 *
 * 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.
 */

#include <ethosu.hpp>
#include <uapi/ethosu.h>

#include <cstring>
#include <iostream>
#include <list>
#include <memory>
#include <sstream>
#include <stdio.h>
#include <string>
#include <unistd.h>

#include "input.h"
#include "model.h"
#include "output.h"
#include "test_assertions.hpp"

using namespace EthosU;

namespace {

int64_t defaultTimeout = 60000000000;

void testPing(const Device &device) {
    int r;
    try {
        r = device.ioctl(ETHOSU_IOCTL_PING);
    } catch (std::exception &e) { throw TestFailureException("Ping test: ", e.what()); }

    TEST_ASSERT(r == 0);
}

void testCapabilties(const Device &device) {
    Capabilities capabilities;
    try {
        capabilities = device.capabilities();
    } catch (std::exception &e) { throw TestFailureException("Capabilities test: ", e.what()); }

    TEST_ASSERT(capabilities.hwId.architecture > SemanticVersion());
}

void testNetworkInfoNotExistentIndex(const Device &device) {
    try {
        Network(device, 0);
        FAIL();
    } catch (Exception &e) {
        // good it should have thrown
    } catch (std::exception &e) { throw TestFailureException("NetworkInfo no index test: ", e.what()); }
}

void testNetworkInfoBuffer(const Device &device) {
    try {
        std::shared_ptr<Buffer> buffer = std::make_shared<Buffer>(device, sizeof(networkModelData));
        buffer->resize(sizeof(networkModelData));
        std::memcpy(buffer->data(), networkModelData, sizeof(networkModelData));
        Network network(device, buffer);

        TEST_ASSERT(network.getIfmDims().size() == 1);
        TEST_ASSERT(network.getOfmDims().size() == 1);
    } catch (std::exception &e) { throw TestFailureException("NetworkInfo buffer test: ", e.what()); }
}

void testNetworkInfoUnparsableBuffer(const Device &device) {
    try {
        auto buffer = std::make_shared<Buffer>(device, sizeof(networkModelData) / 4);
        buffer->resize(sizeof(networkModelData) / 4);
        std::memcpy(buffer->data(), networkModelData + sizeof(networkModelData) / 4, sizeof(networkModelData) / 4);

        try {
            Network network(device, buffer);
            FAIL();
        } catch (Exception) {
            // good, it should have thrown!
        }
    } catch (std::exception &e) { throw TestFailureException("NetworkInfo unparsable buffer test: ", e.what()); }
}

void testRunInferenceBuffer(const Device &device) {
    try {
        auto networkBuffer = std::make_shared<Buffer>(device, sizeof(networkModelData));
        networkBuffer->resize(sizeof(networkModelData));
        std::memcpy(networkBuffer->data(), networkModelData, sizeof(networkModelData));
        auto network = std::make_shared<Network>(device, networkBuffer);

        std::vector<std::shared_ptr<Buffer>> inputBuffers;
        std::vector<std::shared_ptr<Buffer>> outputBuffers;

        auto inputBuffer = std::make_shared<Buffer>(device, sizeof(inputData));
        inputBuffer->resize(sizeof(inputData));
        std::memcpy(inputBuffer->data(), inputData, sizeof(inputData));

        inputBuffers.push_back(inputBuffer);
        outputBuffers.push_back(std::make_shared<Buffer>(device, sizeof(expectedOutputData)));
        std::vector<uint8_t> enabledCounters(Inference::getMaxPmuEventCounters());

        auto inference = std::make_shared<Inference>(network,
                                                     inputBuffers.begin(),
                                                     inputBuffers.end(),
                                                     outputBuffers.begin(),
                                                     outputBuffers.end(),
                                                     enabledCounters,
                                                     false);

        bool timedout = inference->wait(defaultTimeout);
        TEST_ASSERT(!timedout);

        InferenceStatus status = inference->status();
        TEST_ASSERT(status == InferenceStatus::OK);

        bool success = inference->cancel();
        TEST_ASSERT(!success);

        TEST_ASSERT(std::memcmp(expectedOutputData, outputBuffers[0]->data(), sizeof(expectedOutputData)) == 0);

    } catch (std::exception &e) { throw TestFailureException("Inference run test: ", e.what()); }
}

} // namespace

int main() {
    Device device;

    try {
        testPing(device);
        testCapabilties(device);
        testNetworkInfoNotExistentIndex(device);
        testNetworkInfoBuffer(device);
        testNetworkInfoUnparsableBuffer(device);
        testRunInferenceBuffer(device);
    } catch (TestFailureException &e) {
        std::cerr << "Test failure: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
