// 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 "mtd_util.hpp"

#include "fs.hpp"
#include "sys.hpp"

#include <fcntl.h>
#include <mtd/mtd-user.h>

#include <algorithm>
#include <cstring>
#include <format>
#include <stdexcept>
#include <string>

namespace google
{
namespace hoth
{
namespace internal
{

// Sysfs directory containing info about mtd devices
auto constexpr sysfsMtd = "/sys/class/mtd";

std::string MtdImpl::findPartition(const std::string& name)
{
    auto dirs = listDir(sysfsMtd);

    for (const auto& p : dirs)
    {
        std::string line;

        try
        {
            line = getFirstLine(p / "name");
        }
        catch (const std::ios_base::failure& e)
        {
            // If we fail to read a name, just try the next one
            continue;
        }

        if (line == name)
        {
            return p.root_path() / "dev" / p.filename();
        }
    }

    throw std::runtime_error(
        std::format("Unable to find partition with name \"{}\"", name));
}

// TODO: choose the best block size
constexpr size_t blockSize = 4 * 1024;

void MtdImpl::flashCopy(const Sys* sys, const std::vector<uint8_t>& data,
                        const std::string& device)
{
    int fd = sys->open(device.c_str(), O_RDWR | O_SYNC);

    if (fd < 0)
    {
        throw errnoException(std::format("Failed to open device {}", device));
    }

    mtd_info_t mtd;
    if (sys->ioctl(fd, MEMGETINFO, &mtd) < 0)
    {
        sys->close(fd);

        throw errnoException(std::format("Failed to get info on {}", device));
    }

    if (data.size() > mtd.size)
    {
        sys->close(fd);

        throw std::runtime_error(std::format(
            "Data size {} too large for device {}", data.size(), device));
    }

    erase_info_t erase;
    erase.start = 0;
    erase.length = mtd.size;
    if (sys->ioctl(fd, MEMERASE, &erase) < 0)
    {
        sys->close(fd);

        throw errnoException(
            std::format("Failed to erase mtd device {}", device));
    }

    size_t count = 0;
    while (count < data.size())
    {
        size_t writeSize = std::min(data.size() - count, blockSize);
        auto ret = sys->write(fd, data.data() + count, writeSize);

        if (ret < 0)
        {
            if (errno == EINTR)
            {
                continue; // interrupted; try again
            }
            sys->close(fd);

            throw errnoException(
                std::format("Failed to write to mtd device {}", device));
        }
        if (ret == 0) 
        {
            sys->close(fd);

            throw std::runtime_error(std::format(
                "Unexpected EOF while writing to mtd device {}", device));
        } // ret > 0
        count += ret;
    }

    // Validate written data
    std::vector<uint8_t> readBuffer(blockSize);

    // Reset the file descriptor offset back to 0 before reading
    sys->lseek(fd, 0, SEEK_SET);

    count = 0;
    while (count < data.size())
    {
        size_t readSize = std::min(data.size() - count, blockSize);
        auto ret = sys->read(fd, readBuffer.data(), readSize);

        if (ret < 0)
        {
            if (errno == EINTR)
            {
                continue; // interrupted; try again
            }
            sys->close(fd);

            throw errnoException(
                std::format("Failed to read from mtd device {}", device));
        }
        if (ret == 0)
        {
            sys->close(fd);

            throw std::runtime_error(std::format(
                "Unexpected EOF while reading from mtd device {}", device));
        } // ret > 0
        int rc = std::memcmp(data.data() + count, readBuffer.data(), ret);
        if (rc != 0)
        {
            sys->close(fd);

            throw std::runtime_error(
                std::format("Written data failed validation at {} bytes", count));
        }
        count += ret;
    }

    auto retClose = sys->close(fd);
    if (retClose < 0)
    {
        throw errnoException(std::format("Failed to close device {}", device));
    }
}

MtdImpl mtdImpl;

} // namespace internal

} // namespace hoth

} // namespace google
