// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once

#include "storage/storage_encryption.h"
#include "base/bytes.h"
#include "base/optional.h"
#include "base/file_lock.h"

namespace Storage {

class File {
public:
	enum class Mode {
		Read,
		ReadAppend,
		Write,
	};
	enum class Result {
		Failed,
		LockFailed,
		WrongKey,
		Success,
	};
	Result open(const QString &path, Mode mode, const EncryptionKey &key);

	size_type read(bytes::span bytes);
	bool write(bytes::span bytes);

	size_type readWithPadding(bytes::span bytes);
	bool writeWithPadding(bytes::span bytes);

	bool flush();

	bool isOpen() const;
	int64 size() const;
	int64 offset() const;
	bool seek(int64 offset);

	void close();

	static bool Move(const QString &from, const QString &to);

private:
	Result attemptOpen(Mode mode, const EncryptionKey &key);
	Result attemptOpenForRead(const EncryptionKey &key);
	Result attemptOpenForReadAppend(const EncryptionKey &key);
	Result attemptOpenForWrite(const EncryptionKey &key);

	bool writeHeader(const EncryptionKey &key);
	Result readHeader(const EncryptionKey &key);

	size_type readPlain(bytes::span bytes);
	size_type writePlain(bytes::const_span bytes);
	void decrypt(bytes::span bytes);
	void encrypt(bytes::span bytes);
	void decryptBack(bytes::span bytes);

	QFile _data;
	base::FileLock _lock;
	int64 _encryptionOffset = 0;
	int64 _dataSize = 0;

	std::optional<CtrState> _state;

};

} // namespace Storage
