#include <iostream>
#include "ATM.h"

int main() {
    ATM atm;
    atm.run();
    return 0;
}

#ifndef ATM_H
#define ATM_H

class ATM {
public:
    void run();
};

#endif //ATM_H

#include <iostream>
#include "ATM.h"
#include "User.h"
#include "Database.h"

void ATM::run() {
    Database db("atm.db");
    int choice;

    while (true) {
        std::cout << "\nWelcome to the Simple ATM Machine\n";
        std::cout << "1. Deposit\n";
        std::cout << "2. Withdraw\n";
        std::cout << "3. Check Balance\n";
        std::cout << "4. Exit\n";
        std::cout << "Enter your choice: ";
        std::cin >> choice;

        switch (choice) {
            case 1:
                db.deposit();
                break;
            case 2:
                db.withdraw();
                break;
            case 3:
                db.checkBalance();
                break;
            case 4:
                exit(0);
            default:
                std::cout << "Invalid choice. Please try again.\n";
        }
    }
}

#ifndef DATABASE_H
#define DATABASE_H

#include <string>
#include "sqlite3.h"

class Database {
public:
    explicit Database(const std::string &filename);
    ~Database();
    void deposit();
    void withdraw();
    void checkBalance();

private:
    sqlite3 *db;
};

#endif //DATABASE_H

#include <iostream>
#include "Database.h"

static int callback(void *data, int argc, char **argv, char **azColName) {
    for (int i = 0; i < argc; i++) {
        std::cout << azColName[i] << ": " << (argv[i] ? argv[i] : "NULL") << "\n";
    }
    return 0;
}

Database::Database(const std::string &filename) {
    if (sqlite3_open(filename.c_str(), &db)) {
        std::cerr << "Can't open database: " << sqlite3_errmsg(db) << "\n";
        exit(1);
    }

    const char *sql = "CREATE TABLE IF NOT EXISTS USERS(" \
                      "ID INTEGER PRIMARY KEY AUTOINCREMENT," \
                      "BALANCE REAL);";

    char *errMsg = nullptr;
    if (sqlite3_exec(db, sql, callback, nullptr, &errMsg) != SQLITE_OK) {
        std::cerr << "SQL error: " << errMsg << "\n";
        sqlite3_free(errMsg);
    }
}

Database::~Database() {
    sqlite3_close(db);
}

void Database::deposit() {
    double amount;
    std::cout << "Enter the amount to deposit: ";
    std::cin >> amount;

    const char *sql = "INSERT INTO USERS (BALANCE) VALUES (?);";
    sqlite3_stmt *stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_double(stmt, 1, amount);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        std::cerr << "SQL error while depositing\n";
    } else {
        std::cout << "Amount deposited successfully.\n";
    }

    sqlite3_finalize(stmt);
}

void Database::withdraw() {
    double amount;
    std::cout << "Enter the amount to withdraw: ";
    std::cin >> amount;

    // You can add more logic here to check for sufficient balance before withdrawing

    const char *sql = "UPDATE USERS SET BALANCE = BALANCE - ? WHERE ID = (SELECT MAX(ID) FROM USERS);";
    sqlite3_stmt *stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_double(stmt, 1, amount);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        std::cerr << "SQL error while withdrawing\n";
    } else {
        std::cout << "Amount withdrawn successfully.\n";
    }

    sqlite3_finalize(stmt);
}

void Database::checkBalance() {
    const char *sql = "SELECT BALANCE FROM USERS WHERE ID = (SELECT MAX(ID) FROM USERS);";
    char *errMsg = nullptr;
    if (sqlite3_exec(db, sql, callback, nullptr, &errMsg) != SQLITE_OK) {
        std::cerr << "SQL error: " << errMsg << "\n";
        sqlite3_free(errMsg);
    }
}
#include <iostream>
#include "ATM.h"

int main() {
    ATM atm;
    atm.run();
    return 0;
}

#ifndef ATM_H
#define ATM_H

class ATM {
public:
    void run();
};

#endif //ATM_H

#include <iostream>
#include "ATM.h"
#include "User.h"
#include "Database.h"

void ATM::run() {
    Database db("atm.db");
    int choice;

    while (true) {
        std::cout << "\nWelcome to the Simple ATM Machine\n";
        std::cout << "1. Deposit\n";
        std::cout << "2. Withdraw\n";
        std::cout << "3. Check Balance\n";
        std::cout << "4. Exit\n";
        std::cout << "Enter your choice: ";
        std::cin >> choice;

        switch (choice) {
            case 1:
                db.deposit();
                break;
            case 2:
                db.withdraw();
                break;
            case 3:
                db.checkBalance();
                break;
            case 4:
                exit(0);
            default:
                std::cout << "Invalid choice. Please try again.\n";
        }
    }
}

#ifndef DATABASE_H
#define DATABASE_H

#include <string>
#include "sqlite3.h"

class Database {
public:
    explicit Database(const std::string &filename);
    ~Database();
    void deposit();
    void withdraw();
    void checkBalance();

private:
    sqlite3 *db;
};

#endif //DATABASE_H

#include <iostream>
#include "Database.h"

static int callback(void *data, int argc, char **argv, char **azColName) {
    for (int i = 0; i < argc; i++) {
        std::cout << azColName[i] << ": " << (argv[i] ? argv[i] : "NULL") << "\n";
    }
    return 0;
}

Database::Database(const std::string &filename) {
    if (sqlite3_open(filename.c_str(), &db)) {
        std::cerr << "Can't open database: " << sqlite3_errmsg(db) << "\n";
        exit(1);
    }

    const char *sql = "CREATE TABLE IF NOT EXISTS USERS(" \
                      "ID INTEGER PRIMARY KEY AUTOINCREMENT," \
                      "BALANCE REAL);";

    char *errMsg = nullptr;
    if (sqlite3_exec(db, sql, callback, nullptr, &errMsg) != SQLITE_OK) {
        std::cerr << "SQL error: " << errMsg << "\n";
        sqlite3_free(errMsg);
    }
}

Database::~Database() {
    sqlite3_close(db);
}

void Database::deposit() {
    double amount;
    std::cout << "Enter the amount to deposit: ";
    std::cin >> amount;

    const char *sql = "INSERT INTO USERS (BALANCE) VALUES (?);";
    sqlite3_stmt *stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_double(stmt, 1, amount);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        std::cerr << "SQL error while depositing\n";
    } else {
        std::cout << "Amount deposited successfully.\n";
    }

    sqlite3_finalize(stmt);
}

void Database::withdraw() {
    double amount;
    std::cout << "Enter the amount to withdraw: ";
    std::cin >> amount;

    // You can add more logic here to check for sufficient balance before withdrawing

    const char *sql = "UPDATE USERS SET BALANCE = BALANCE - ? WHERE ID = (SELECT MAX(ID) FROM USERS);";
    sqlite3_stmt *stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_double(stmt, 1, amount);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        std::cerr << "SQL error while withdrawing\n";
    } else {
        std::cout << "Amount withdrawn successfully.\n";
    }

    sqlite3_finalize(stmt);
}

void Database::checkBalance() {
    const char *sql = "SELECT BALANCE FROM USERS WHERE ID = (SELECT MAX(ID) FROM USERS);";
    char *errMsg = nullptr;
    if (sqlite3_exec(db, sql, callback, nullptr, &errMsg) != SQLITE_OK) {
        std::cerr << "SQL error: " << errMsg << "\n";
        sqlite3_free(errMsg);
    }
}