#include <iostream>
#include <fstream>

#include "sys.hpp"
#include "buffer.hpp"
#include "cryptography.hpp"
#include "func.hpp"
#include "arg_func.hpp"

#define DEBUG 0

int main(int argc, char **argv)
{
	std::string user_pass = "";
	char *label = nullptr;
	Arg args = Arg::Error;
	std::optional<std::string> save_location_path = std::nullopt;
	std::string save_location = "";

#if DEBUG

	user_pass = "123";
	args = Arg::Print_all_p;
	std::string label_st = "facebook";
	label = label_st.data();
	save_location = "passwords.bin";

#else

	args = get_args(argc, argv, &label);
	if (args == Arg::Error)
		return 0;

	save_location_path = get_save_path();
	if (!save_location_path.has_value())
	{
		printf("Error geting file for save path\n");
		return 1;
	}

	std::ifstream ifile(save_location_path.value(), std::ios::binary);
	if (ifile.is_open())
	{
		std::getline(ifile, save_location);
		ifile.close();
	}

	if (save_location.empty() && args != Arg::File)
	{
		printf("No save location, try selecting save folder (-f)\n");
		return 1;
	}

#endif // DEBUG

	Buffer encrypted_buffer;
	// load file
	if (!encrypted_buffer.load_from_file(save_location))
		// if file doesn't exist, check if it's a new password is being generated if not, exit
		if (!(args == Arg::Generate || args == Arg::Input || args == Arg::File))
		{
			printf("No passwords, try generating password (-g or -i)\n");
			return 1;
		}

#if !DEBUG
	printf("Input main password:");
	user_pass = get_user_password();
	if (user_pass.empty())
	{
		printf("Error getting password\n");
		return 1;
	}
#endif // !1

	Cryptography crypto(user_pass);

	Buffer decrypted_buffer;
	// check if encrypted buffer is empty if not, decrypt it
	if (encrypted_buffer.size > 0)
		if (!crypto.decrypt(&encrypted_buffer, &decrypted_buffer))
			return 1;

	// if decrypted buffer is empty, add index
	if (decrypted_buffer.taken < sizeof(Index))
	{
		Index index = {0};
		index.offset = sizeof(Index);
		decrypted_buffer.add_end((uint8_t *)&index, sizeof(Index));
	}

	std::optional<LoginInfoPointer> login_info;

	switch (args)
	{
	case Arg::Get:
		login_info = arg_get(decrypted_buffer, label);
		break;

	case Arg::Generate:
		login_info = arg_new_password(decrypted_buffer, encrypted_buffer, label, crypto, true);
		break;

	case Arg::List:
		arg_list(decrypted_buffer);
		break;

	case Arg::Delete:
		arg_delete(decrypted_buffer, encrypted_buffer, label, crypto);
		break;

	case Arg::Print_all_p:
		arg_print_all_p(decrypted_buffer, user_pass);
		break;

	case Arg::Input:
		login_info = arg_new_password(decrypted_buffer, encrypted_buffer, label, crypto, false);
		break;

	case Arg::Username:
		arg_username(decrypted_buffer, encrypted_buffer, label, crypto);
		break;

	case Arg::Name:
		arg_label_name(decrypted_buffer, encrypted_buffer, label, crypto);
		break;

	case Arg::Change:
		arg_change(decrypted_buffer, encrypted_buffer, user_pass, crypto);
		break;

	case Arg::Show:
		arg_show(decrypted_buffer, label);
		break;

	case Arg::File:
		arg_file(decrypted_buffer, encrypted_buffer, label, crypto, save_location_path.value());
		break;
	}

	if (!login_info.has_value())
		return 0;

#if DEBUG

	printf("Username: %s\n", login_info.value().username);
	printf("Password: %s\n", login_info.value().password);

#else

	printf("Username: %s\n", login_info.value().username);
	put_data_on_clipboard(login_info.value().password);
	printf("Password copied to clipboard\n");

#endif // _DEBUG

	return 0;
}