// Copyright 2022, FOSS-VG Developers and Contributers
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

#include <vector>
#include "assert.hpp"
#include "tinyutf8/tinyutf8.h"
#include "../lib/file.hpp"

int main(){
    std::cout << "################################################################################" << std::endl;
    std::cout << "File tests" << std::endl;
    std::cout << "################################################################################" << std::endl;
    File* file;

    //readByte test
    file = File::open("resources/unicode_data/normal_utf-8", 'r').value;
    uint8_t byte = file->readByte().value;
    ASSERT(byte == 'T');
    std::cout << "Passed read byte test." << std::endl;

    //read test
    std::vector<uint8_t> bytes = file->read(5).value;
    //cursorPosition has already moved forward by one
    ASSERT(bytes == std::vector<uint8_t>({'e', 's', 't', ' ', 's'}));
    std::cout << "Passed read test." << std::endl;

    //readString test
    tiny_utf8::string data = file->readString(5).value;
    ASSERT(data == "tring");
    std::cout << "Passed read string test." << std::endl;
    file->close();
    delete file;

    //Write Tests
    File *writeFile;
    File *readFile;

    //writeByte test
    writeFile = File::open("resources/writeTest", 'w').value;
    writeFile->writeByte('a');
    writeFile->close();

    readFile = File::open("resources/writeTest", 'r').value;
    uint8_t testByte = readFile->readByte().value;
    readFile->close();
    ASSERT(testByte == 'a');
    std::cout << "Passed write byte test." << std::endl;

    //write test
    writeFile->open();
    writeFile->write(std::vector<uint8_t>({'a', 'b', 'c'}));
    writeFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string testBytes = readFile->readString(3).value;
    readFile->close();
    ASSERT(testBytes == "abc");
    std::cout << "Passed write test." << std::endl;

    writeFile->open();
    writeFile->writeString(tiny_utf8::string("Hallo"));
    writeFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string testString = readFile->readString(5).value;
    readFile->close();
    ASSERT(testString == "Hallo");
    std::cout << "Passed write string test." << std::endl;

    delete writeFile;

    File *appendFile;

    appendFile = File::open("resources/writeTest", 'a').value;
    appendFile->writeByte(',');
    appendFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string appendByteString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(appendByteString == "Hallo,");
    std::cout << "Passed append byte test." << std::endl;

    appendFile->open();
    appendFile->write(std::vector<uint8_t>({' ', 'I', 'c', 'h'}));
    appendFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string appendBytesString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(appendBytesString == "Hallo, Ich");
    std::cout << "Passed append test" << std::endl;

    appendFile->open();
    appendFile->writeString(" bin Shwoomple.");
    appendFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string appendString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(appendString == "Hallo, Ich bin Shwoomple.");
    std::cout << "Passed append string test" << std::endl;

    delete appendFile;

    //test insert functions
    File *modifyFile;

    modifyFile = File::open("resources/writeTest", 'm').value;

    modifyFile->cursorPosition = 5;
    modifyFile->insertByte(',');
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string modifyByteString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(modifyByteString == "Hallo,, Ich bin Shwoomple.");
    std::cout << "Passed modify byte test" << std::endl;

    modifyFile->open();
    modifyFile->cursorPosition = 6;
    modifyFile->insert(std::vector<uint8_t>({' ', 'H', 'i'}));
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string modifyBytesString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(modifyBytesString == "Hallo, Hi, Ich bin Shwoomple.");
    std::cout << "Passed modify test" << std::endl;

    modifyFile->open();
    modifyFile->cursorPosition = 9;
    modifyFile->insertString(" THE CAKE IS A LIE");
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string modifyString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(modifyString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple.");
    std::cout << "Passed modify string test" << std::endl;

    //test cut functions
    modifyFile->open();
    modifyFile->cursorPosition = modifyFile->size.value-1;
    ErrorOr<uint8_t> cutByte = modifyFile->cutByte();
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value;
    readFile->close();    

    ASSERT(modifyFile->cursorPosition == modifyFile->size.value);
    ASSERT(cutByte.value == '.');
    ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple");
    std::cout << "Passed cut byte test." << std::endl;

    modifyFile->open();
    modifyFile->cursorPosition = 9;
    ErrorOr<std::vector<uint8_t>> cutBytes = modifyFile->cut(18);
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string cutBytesString = readFile->readString(readFile->size.value).value;
    readFile->close();


    ASSERT(modifyFile->cursorPosition == 9);
    ASSERT(cutBytes.value == std::vector<uint8_t>({' ', 'T', 'H', 'E', ' ', 'C', 'A', 'K', 'E', ' ', 'I', 'S', ' ','A', ' ', 'L', 'I', 'E'}))
    ASSERT(cutBytesString == "Hallo, Hi, Ich bin Shwoomple");
    std::cout << "Passed cut test." << std::endl;

    modifyFile->open();
    modifyFile->cursorPosition = 0;
    ErrorOr<tiny_utf8::string> cutString = modifyFile->cutString(7);
    modifyFile->close();

    readFile->open();
    readFile->cursorPosition = 0;
    tiny_utf8::string cutReadString = readFile->readString(readFile->size.value).value;
    readFile->close();

    ASSERT(modifyFile->cursorPosition == 0);
    ASSERT(cutString.value == "Hallo, ");
    ASSERT(cutReadString == "Hi, Ich bin Shwoomple");
    std::cout << "Passed cutString test." << std::endl;
}
