#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ERRORRETURN 10787253
#define ARRSIZE 4096
#define EXITVAL 15326
#define ENOCUSTOMER 692137
#define ENOPRODUCT 691337

struct Product {
    int id;
    char* name;
    double price;
    int amount;
};

struct Customer {
    char* name;
    int id;
};

int find_first_free_customer(struct Customer* array[]) {
    for (int i = 0; i < ARRSIZE; i++) {
        if (array[i] == NULL) {
            return i;
        }
    }
    return -1;
}

int find_first_free_product(struct Product* array[]) {
    for (int i = 0; i < ARRSIZE; i++) {
        if (array[i] == NULL) {
            return i;
        }
    }
    return -1;
}

int find_product_index(int id, struct Product* array[]) {
    for (int i = 0; i < ARRSIZE; i++) {
        if (array[i] != NULL && array[i]->id == id) {
            return i;
        }
    }
    errno = ENOPRODUCT;
    printf("Mit der eingegeben Produktnummer konnte kein Produkt gefunden werden.\n");
    return ERRORRETURN;
}

int find_customer_index(int id, struct Customer* array[]) {
    for (int i = 0; i < ARRSIZE; i++) {
        if (array[i] != NULL && array[i]->id == id) {
            return i;
        }
    }
    errno = ENOCUSTOMER;
    printf("Mit der eingegeben Kundennummer konnte kein Kunde gefunden werden.\n");
    return ERRORRETURN;
}

int add_product(struct Product* products[]) {
    int id, amount;
    char name[100];
    double price;

    printf("**********************\n");
    printf("* WWS Produkteingabe *\n");
    printf("**********************\n");
    printf("Bitte geben Sie eine Produktnummer ein: ");
    scanf("%d", &id);
    printf("Bitte geben Sie einen Produktnamen ein: ");
    scanf("%99s", name);
    printf("Bitte geben Sie einen Preis für das Produkt ein: ");
    scanf("%lf", &price);
    printf("Bitte geben Sie die aktuelle Anzahl im Inventar: ");
    scanf("%d", &amount);

    struct Product* new_product = (struct Product*)malloc(sizeof(struct Product));
    if (!new_product) {
        printf("Fehler beim Speicher zuweisen.");
        errno = ENOMEM;
        return ERRORRETURN;
    }

    new_product->id = id;
    new_product->name = strdup(name); // Duplicate string to avoid issues.
    new_product->price = price;
    new_product->amount = amount;

    int index = find_first_free_product(products);
    if (index == -1) {
        free(new_product);
        printf("Kein freier Platz für Produkte.");
        errno = ENOMEM;
        return ERRORRETURN;
    }

    products[index] = new_product;
    return 0;
}

int add_customer(struct Customer* customers[]) {
    int id;
    char name[100];

    printf("*********************\n");
    printf("* WWS Kundeneingabe *\n");
    printf("*********************\n");
    printf("Bitte geben Sie eine Kundennummer ein: ");
    scanf("%d", &id);
    printf("Bitte geben Sie einen Kundennamen ein: ");
    scanf("%99s", name);

    struct Customer* new_customer = (struct Customer*)malloc(sizeof(struct Customer));
    if (!new_customer) {
        printf("Fehler beim Speicher zuweisen.");
        errno = ENOMEM;
        return ERRORRETURN;
    }

    new_customer->id = id;
    new_customer->name = strdup(name); // Duplicate string to avoid issues.

    int index = find_first_free_customer(customers);
    if (index == -1) {
        free(new_customer);
        printf("Kein freier Platz für Kunden.");
        errno = ENOMEM;
        return ERRORRETURN;
    }

    customers[index] = new_customer;
    return 0;
}

int print_product(struct Product* products[]) {
    int id;

    printf("**********************\n");
    printf("* WWS Produktausgabe *\n");
    printf("**********************\n");
    printf("Bitte geben Sie die gesuchte Produktnummer ein: ");
    scanf("%d", &id);

    int index = find_product_index(id, products);
    if (index == ERRORRETURN) {
        return ERRORRETURN;
    }

    struct Product* product = products[index];
    printf("======================\n");
    printf("Produktnummer: %d\n", product->id);
    printf("Name: %s\n", product->name);
    printf("Einzelpreis: %.2lf\n", product->price);
    printf("Anzahl: %d\n", product->amount);
    printf("Gesamtpreis: %.2lf\n", product->price * product->amount);

    return 0;
}

int print_customer(struct Customer* customers[]) {
    int id;

    printf("*********************\n");
    printf("* WWS Kundenausgabe *\n");
    printf("*********************\n");
    printf("Bitte geben Sie die gesuchte Kundennummer ein: ");
    scanf("%d", &id);

    int index = find_customer_index(id, customers);
    if (index == ERRORRETURN) {
        return ERRORRETURN;
    }

    struct Customer* customer = customers[index];
    printf("=====================\n");
    printf("Kundennummer: %d\n", customer->id);
    printf("Name: %s\n", customer->name);

    return 0;
}

int menu(struct Customer* customers[], struct Product* products[]) {
    int input;

    printf("**********************\n");
    printf("* TH Warenwirtschaft *\n");
    printf("**********************\n");
    printf("Optionen:\n");
    printf("1. Produkteingabe\n");
    printf("2. Kundeneingabe\n");
    printf("3. Produktausgabe\n");
    printf("4. Kundenausgabe\n");
    printf("5. Verlassen\n");
    printf("Eingabe: ");
    scanf("%d", &input);

    errno = 0;

    switch (input) {
        case 1:
            add_product(products);
            if (errno != 0) {return ERRORRETURN;}
            break;
        case 2:
            add_customer(customers);
            if (errno != 0) {return ERRORRETURN;}
            break;
        case 3:
            print_product(products);
            if (errno != 0) {return ERRORRETURN;}
            break;
        case 4:
            print_customer(customers);
            if (errno != 0) {return ERRORRETURN;}
            break;
        case 5:
            return EXITVAL;
        default:
            printf("Ungültige Eingabe. Bitte erneut versuchen.\n");
            break;
    }

    return 0;
}

int main() {
    errno = 0;
    int menuval = 0;
    struct Customer* customers[ARRSIZE] = {NULL};
    struct Product* products[ARRSIZE] = {NULL};

    while (menuval == 0) {
        menuval = menu(customers, products);
    }

    return errno;
}
