// Copyright 2024 Google LLC
//
// 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.

#include "utils.hpp"

#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>

#include <optional>
#include <set>

extern "C"
{
#include <i2c/smbus.h>
#include <linux/i2c-dev.h>
}

constexpr static char daemonType[] = "USBReset";

// a set of i2c<bus, addr> indicating if the i2c device has been intiated or not
// the set is used to ensure each USBHub just get reset once per power-up
std::set<std::pair<int, int>> initSet;

static std::optional<int>
    extractBusNumber(const std::string& path,
                     const SensorBaseConfigMap& properties)
{
    auto findBus = properties.find("Bus");
    if (findBus == properties.end())
    {
        std::cerr << "could not determine bus number for " << path << "\n";
        return std::nullopt;
    }

    return std::visit(VariantToIntVisitor(), findBus->second);
}

static std::optional<int> extractAddress(const std::string& path,
                                         const SensorBaseConfigMap& properties)
{
    auto findAddr = properties.find("Address");
    if (findAddr == properties.end())
    {
        std::cerr << "could not determine address for " << path << "\n";
        return std::nullopt;
    }

    return std::visit(VariantToIntVisitor(), findAddr->second);
}

void resetUSBHub(int i2cBus, int i2cAddr)
{
    std::cerr << "resetting i2c device: " << i2cBus << ", " << i2cAddr << '\n';

    std::filesystem::path devpath = "/dev/i2c-" + std::to_string(i2cBus);

    int fd = ::open(devpath.c_str(), std::ios_base::in | std::ios_base::out);
    if (fd < 0) {
        std::cerr << "fail to open i2c device: " << i2cBus << ", " << i2cAddr
                << '\n';
        return;
    }

    /* Select the target device */
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
    if (::ioctl(fd, I2C_SLAVE_FORCE, i2cAddr) < 0)
    {
        std::cerr << "Failed to configure device address 0x" << std::hex
                  << i2cAddr << " for bus " << std::dec << i2cBus << ": "
                  << strerror(errno) << "\n";
        return;
    }

    // retry max 5 times
    int i = 0;
    int res = -1;
    for (; i < 5; i++)
    {
        if (i > 0)
        {
          std::cerr << "retry the reset command" << '\n';
        }
        res = i2c_smbus_write_byte_data(fd, 0x01, 0x00);
        if (res < 0)
        {
            std::cerr
                << "Failed to set output register to all zero on address 0x"
                << std::hex << i2cAddr << " for bus " << std::dec << i2cBus
                << ": " << strerror(-res) << "\n";
            continue;
        }

        res = i2c_smbus_write_byte_data(fd, 0x03, 0xfe);
        if (res < 0)
        {
            std::cerr << "Failed to asserts USB Hub reset on address 0x"
                      << std::hex << i2cAddr << " for bus " << std::dec
                      << i2cBus << ": " << strerror(-res) << "\n";
            continue;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        res = i2c_smbus_write_byte_data(fd, 0x01, 0x01);
        if (res < 0)
        {
            std::cerr << "Failed to deasserts USB Hub reset on address 0x"
                      << std::hex << i2cAddr << " for bus " << std::dec
                      << i2cBus << ": " << strerror(-res) << "\n";
            continue;
        }
        break;
    }

    if (i >= 5)
    {
        std::cerr << "Failed to send reset command to address 0x" << std::hex
                  << i2cAddr << " for bus " << std::dec << i2cBus << "\n";
    }

    ::close(fd);
}

void handler(const std::shared_ptr<sdbusplus::asio::connection> &bus)
{

    auto getter = std::make_shared<GetSensorConfiguration>(
        bus, [](const ManagedObjectType &configurations)
    {
        if (!readingStateGood(PowerState::on))
        {
            return;
        }

        for (const auto &[path, configData] : configurations)
        {
            auto find = configData.find(configInterfaceName(daemonType));
            if (find == configData.end())
            {
                continue;
            }
            const auto &config = find->second;
            auto i2cBus = extractBusNumber(path, config);
            auto i2cAddr = extractAddress(path, config);

            if (!i2cBus || !i2cAddr)
            {
                std::cerr << "failed to find i2c bus info: continue" << '\n';
                continue;
            }
            auto initiated = initSet.find({*i2cBus, *i2cAddr});
            if (initiated != initSet.end())
            {
                continue;
            }
            resetUSBHub(*i2cBus, *i2cAddr);
            initSet.emplace(*i2cBus, *i2cAddr);
        }
    });
    getter->getConfiguration(std::vector<std::string>{daemonType});
}

int main()
{
    boost::asio::io_service io;
    auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
    sdbusplus::asio::object_server objectServer(systemBus, true);

    [[maybe_unused]] auto powerCb =
        setupPowerMatchCallback(systemBus, [&](PowerState type, bool state) {
            if (type != PowerState::on)
            {
                return;
            }

            // clear the initSet when the Host power is done
            if (!state)
            {
                initSet.clear();
            }
            else
            {
                handler(systemBus);
            }
        });

    std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
        setupPropertiesChangedMatches(
            *systemBus, std::to_array<const char*>({daemonType}),
            [&](sdbusplus::message_t&) {
                static boost::asio::steady_timer timer(io);
                timer.expires_from_now(std::chrono::seconds(1));
                timer.async_wait([&](const boost::system::error_code& ec) {
                    if (ec == boost::asio::error::operation_aborted)
                    {
                        return; // we're being canceled
                    }

                    if (ec)
                    {
                        std::cerr << "Error: " << ec.message() << "\n";
                        return;
                    }

                    handler(systemBus);
                });
            });
    boost::asio::post(io, [systemBus] { handler(systemBus); });
    io.run();
}
