// SPDX-License-Identifier: BSL-1.0

#include "catchwrapper.h"
#include "../filecategorize.h"

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <QDir>
#include <QFile>
#include <QTemporaryDir>


TEST_CASE("FileOpen") {

    auto slash = GENERATE("", "/");

    //TEMP DIR
    QTemporaryDir dir;
    QDir tmpd(dir.path());

    //RW
    QString dirRW = dir.path() + "/rw";
    tmpd.mkdir("rw");

    QFile tmpf(dirRW + "/filerw");
    QString fileRW = tmpf.fileName();
    tmpf.open(QIODevice::WriteOnly);
    tmpf.close();

    QString fileRWNE = dirRW + "/filenotexist";

    QString dirRWNE = dirRW + "/dirnotexist";

    //RO
    tmpd.mkdir("ro");
    QString dirRO = dir.path() + "/ro";

    QString fileRO = dirRO + "/filero";
    tmpf.setFileName(fileRO);
    tmpf.open(QIODevice::WriteOnly);
    tmpf.close();

    //TODO: root with 0600
    //QString fileNotR = dirRO + "/fileNotR";
    //tmpf.setFileName(fileNotR);
    //tmpf.open(QIODevice::NotOpen);
    //tmpf.close();

    QString fileRONE = dirRO + "/filenotexist";

    QString dirRONE = dirRO + "/dirnotexist";

    chmod(fileRO.toUtf8().data(), 0400);
    chmod(dirRO.toUtf8().data(), 0500);

// Datei
    //RW
    CHECK(fileCategorize(fileRW) == FileCategory::open_file);
    //RO
    CHECK(fileCategorize(fileRO) == FileCategory::open_file);
    //NOT R
    //CHECK(fileCategorize(fileNotR) == FileCategory::invalid_file_not_readable);
    //not exist RW dir
    CHECK(fileCategorize(fileRWNE) == FileCategory::new_file);

    //not exist RO dir /chr
    if ( geteuid() ) {
        CHECK(fileCategorize(fileRONE) == FileCategory::invalid_dir_not_writable);
    }

    //if not a regular file
    CHECK(fileCategorize("/dev/null") == FileCategory::invalid_filetype);

    //file open with slash: test/
    //CHECK(fileCategorize(fileRW + "/") == FileCategory::invalid_dir_not_exist);

// Dir
    //dir
    CHECK(fileCategorize(dirRW + slash) == FileCategory::dir);
    CHECK(fileCategorize(dirRO + slash) == FileCategory::dir);

    //not exist  /chr/chr /chr/chr/
    CHECK(fileCategorize(dirRWNE + "/") == FileCategory::invalid_dir_not_exist);
    CHECK(fileCategorize(dirRONE + "/") == FileCategory::invalid_dir_not_exist);

// Symlink
    {
        auto inrow = GENERATE("/ro", "/rw");
        chmod(dirRO.toUtf8().data(), 0700);

        QString fileLinkRW = dir.path() + inrow + "/linkRW";
        QFile::link(fileRW, fileLinkRW);

        QString fileLinkRO = dir.path() + inrow + "/linkRO";
        QFile::link(fileRO, fileLinkRO);

        QString fileLinkRWNE = dir.path() + inrow + "/linkRWNE";
        QFile::link(fileRWNE, fileLinkRWNE);

        QString fileLinkRONE = dir.path() + inrow + "/linkRONE";
        QFile::link(fileRONE, fileLinkRONE);

        QString dirLinkRW = dir.path() + inrow + "/dirlinkRW";
        QFile::link(dirRW, dirLinkRW);

        QString dirLinkRO = dir.path() + inrow + "/dirlinkRO";
        QFile::link(dirRO, dirLinkRO);

        QString dirLinkRWNE = dir.path() + inrow + "/dirlinkRWNE";
        QFile::link(dirRWNE, dirLinkRWNE);

        QString dirLinkRONE = dir.path() + inrow + "/dirlinkRONE";
        QFile::link(dirRONE, dirLinkRONE);

        QString dirLinkNE = dir.path() + inrow + "/dirlinkNE";
        QFile::link(dir.path() + inrow +"/NE/file", dirLinkNE);

        QString self =  dir.path() + inrow + "/self";
        QFile::link(self, self);

        chmod(dirRO.toUtf8().data(), 0500);

        //to file RW
        CHECK(fileCategorize(fileLinkRW) == FileCategory::open_file);

        //to file RO
        CHECK(fileCategorize(fileLinkRO) == FileCategory::open_file);

        //to dir
        //CAPTURE((dirLinkRW + slash).toUtf8().data());
        CHECK(fileCategorize(dirLinkRW + slash) == FileCategory::dir);
        CHECK(fileCategorize(dirLinkRO + slash) == FileCategory::dir);
        CHECK(fileCategorize(dirLinkRWNE + "/") == FileCategory::invalid_dir_not_exist);
        CHECK(fileCategorize(dirLinkRONE + "/") == FileCategory::invalid_dir_not_exist);

        //to not exist file
        CHECK(fileCategorize(fileLinkRWNE) == FileCategory::new_file);
        if ( geteuid() ) {
            CHECK(fileCategorize(fileLinkRONE) == FileCategory::invalid_dir_not_writable);
        }

        //to not exist dir
        CHECK(fileCategorize(dirLinkNE) == FileCategory::invalid_dir_not_exist);

        //to self
        CHECK(fileCategorize(self) == FileCategory::invalid_error);

        QFileInfo testSelf(self + "/");
        if (testSelf.isSymLink()) {
            // MacOS implements lstat in a way that considers this path to be a symlink (instead of an error with ELOOP)
            // It's ok that fileCategorize reflects this os specific difference.
            CHECK(fileCategorize(self + "/") == FileCategory::invalid_error);
        } else {
            CHECK(fileCategorize(self + "/") == FileCategory::invalid_dir_not_exist);
        }

        CHECK(fileCategorize(self + "/notexist") == FileCategory::invalid_dir_not_exist);
    }

// From STDIN
    CHECK(fileCategorize("-") == FileCategory::stdin_file);

// empty
    CHECK(fileCategorize("") == FileCategory::new_file);

// cleanup
    chmod(dirRO.toUtf8().data(), 0700);
    chmod(fileRO.toUtf8().data(), 0600);
}

TEST_CASE("FileChange") {
    // RO

    // RW

    // change

    // dir delete

}
