//include std lib if they havent been included
#ifndef STD_LIB_H
#define STD_LIB_H
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#endif

#ifndef Utils
#define Utils
#include "sorting.h"
#include "utils.h"
#endif // !Utils
//fucntions for menu
void search_item(void * (*showitem)(void *,int));
void self_help_sale_system();
void print_page(void * ddb, int cur, int end,struct Map* map);
struct Map* sortItems(void * ddb, int sort);

//main of normal user
void normal_menu(){
    int choice = 0;
    do{
        char buf[1024];
        welcome_message(buf);
        sprintf(buf+strlen(buf),"Normal User Menu\n");
		choice = choices_selecter((char*[]){
            "List items",
        	"Search item",
        	"Self help sale system"
        },3,buf);
        switch (choice)
        {
            case 1:;//List items
                struct inventory db = read_db_invt();
                char * SortItems[] = {
                    "Name",
                    "Price",
                    "Brand",
                    "Category",
                };
                lister(&db,NULL,db.db.row_count,"List of items",SortItems,4,print_page,sortItems,show_item);
                break;
            case 2://Search item
                search_item(show_item);
                break;
            case 3://self help sale system
                self_help_sale_system();
                break;
            default://invalid input ,should not happen,as it is already catch in above function
                break;
        }
    }while(choice != 4);
}

//search items
char* prompt_search();
struct Map* searchItems(struct inventory db, char* searchstr);
void search_item(void * (*showitem)(void *,int)){

    //search for item
    //prompt user to select an item
    //if user selects an item, display the item's details
    struct inventory db = read_db_invt();
    struct Map* map = NULL;
    do{

    //options
    int breakout = 0;
    breakout = choices_selecter((char*[]){"Search"},1,welcome_message(NULL));
    if(breakout == 2){
        break;
    }
    char* searchstr = prompt_search();
    printf("searching...\n");
    map = searchItems(db,searchstr);
    if(map[0].value > 0){
        int temp_row = *((int*)map[0].value);
        char * SortItems[] = {
            "Name",
            "Price",
            "Brand",
            "Category",
        };
        lister(&db,map+1,temp_row,"List of items",SortItems,4,print_page,sortItems,showitem);//ofset map, as it is use to store the size
    }else{//empty search
        printf("No result found\n");
        printf("Press any key to continue\n");
        fflush_stdin();
        getchar();

    }
    }while(true);//break on top

}


char* prompt_search(){
    printf("Enter search string:(largest length 100)(case insesitive)\n>");
    char* searchstr = malloc(sizeof(char) * 100);
    fflush_stdin();
    scanf("%s", searchstr);
    return searchstr;
}



struct Map* searchItems(struct inventory db, char* searchstr){
    struct Map* map = malloc(sizeof(struct Map) * (db.db.row_count+1));
    int k = 1;
    for (int i = 0; i < db.db.row_count; i++){
        map[k].key = i;
        if(strcasestr(db.row[i].product,searchstr) != NULL){
            
            map[k].value = (void*)db.row[i].product;
            k++;
        }
    }
    int* k_star = malloc(sizeof(int));
    *k_star = --k;//decrement and assign to k star;don't use k-- as it will decrement after the assignment
    map[0].value = (void*)k_star;
    map[0].key = -1;
    return map;
}

//self help

struct cart* scan_barcode(struct cart* cart,struct inventory db);
struct cart* list_cart(struct cart* cart);
void self_help_sale_system(){
 
    //scan barcode
    struct inventory db = read_db_invt();
    struct cart* cart = NULL;
    int choice = 0;
    do{

    //options
    int breakout = 0;
    choice = choices_selecter((char*[]){
        "scan barcode",
    	"cart/checkout"
    },2,welcome_message(NULL));
    switch (choice)
    {
    case 1:
        cart = scan_barcode(cart,db);
        break;
    case 2:
        cart = list_cart(cart);
        break;
    default:
        break;
    }
    }while(choice!=3);
}

//support for the linked list
struct cart* Cartappend(struct cart* cart,struct inventory_row* row,int quantity){
    if(cart == NULL){
        cart = malloc(sizeof(struct cart));
        cart->row = row;
        cart->quantity = quantity;
        cart->next = NULL;
    }else{
        struct cart* temp = cart;
        while(temp->next != NULL){
            temp = temp->next;
        }
        temp->next = malloc(sizeof(struct cart));
        temp->next->row = row;
        temp->next->quantity = quantity;
        temp->next->next = NULL;
    }

    return cart;
}

struct cart* Cartremove(struct cart* cart,int index){
    if (cart == NULL){
        return cart;
    }else{
        struct cart* temp = cart;
        if (index == 0){
            cart = cart->next;
            free(temp);
            return cart;
        }else{
            for (int i = 0; i < index-1; i++){
                temp = temp->next;
            }
            struct cart* new = temp->next->next;
            free(temp->next);
            temp->next = new;
            return cart;
        }
    }
}
struct cart* Cartupdate(struct cart* cart,int index,int quantity){
    if (cart == NULL){
        return cart;
    }else{
        struct cart* temp = cart;
        if (index == 0){
            cart->quantity = quantity;
            return cart;
        }else{
            for (int i = 0; i < index-1; i++){
                temp = temp->next;
            }
            temp->next->quantity = quantity;
            return cart;
        }
    }
}

struct inventory_row* Cartget(struct cart* cart,int index){
    if (cart == NULL){
        return NULL;
    }else{
        struct cart* temp = cart;
        if (index == 0){
            return cart->row;
        }else{
            for (int i = 0; i < index-1; i++){
                temp = temp->next;
            }
            return temp->next->row;
        }
    }
}

int Cartqty(struct cart* cart,int index){
    if (cart == NULL){
        return 0;
    }else{
        struct cart* temp = cart;
        if (index == 0){
            return cart->quantity;
        }else{
            for (int i = 0; i < index-1; i++){
                temp = temp->next;
            }
            return temp->next->quantity;
        }
    }
}

//scan barcode
struct inventory_row* find_barcode(struct inventory db,long barcode);
long prompt_barcode();
struct cart* scan_barcode(struct cart* cart,struct inventory db){
   
    long barcode = prompt_barcode();
    printf("matching...\n");
    struct inventory_row* row = find_barcode(db,barcode);
    if(row != NULL){
        int quantity = 0; 
        char choice = 'n';
        do{
            Cls();    
            printf("product: %s\n",row->product);
            printf("price: %.1f\n",row->price);
            printf("Enter quantity(0 to cancel)\n>");\
            fflush_stdin();
            scanf("%d", &quantity);
            fflush_stdin();
            if(quantity == 0){
                printf("cancelled\n");
                printf("press any key to continue\n");
                fflush_stdin();
                getchar();
                return cart;
            }
            printf("Are you sure you want to add this item to cart?(y/n)\n>");
            fflush_stdin();
            scanf("%c", &choice);
            if(row->stock - quantity < 0 && choice == 'y'){
                printf("WARNING:not enough stock\n");
                printf("Are you sure the quantity is correct?\n(y to ignore and continue/n)\n>");
                fflush_stdin();
                scanf("%c", &choice);
            }
        }while(choice != 'y');
        if(quantity != 0){
            cart = Cartappend(cart,row,quantity);
            printf("added to cart\n");
        }
    }else{//empty search
        printf("Unable to match or invalid input\n");

    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();
    return cart;
}


long prompt_barcode(){
    printf("Please scan the qr code(or input the barcode) ");
    long barcode;
    fflush_stdin();
    scanf("%ld", &barcode);
    return barcode;
}

struct inventory_row* find_barcode(struct inventory db,long barcode){
    struct inventory_row row;
    for (int i = 0; i < db.db.row_count; i++){
        if(db.row[i].barcode == barcode){
            
            return &db.row[i];
        }
    }
    return (struct inventory_row*)NULL;
}


//list cart
struct cart* cart_control(struct cart* cart,int index);
struct cart* checkout(struct cart* cart);
struct cart* list_cart(struct cart* cart){
        int choice = 0;
    do{
        Cls();
        welcome_message(stdout);
        double total_price = 0;
        int i=1;
        printf("0 exit\n");
        if(cart == NULL){
            printf("Cart is empty\n");
        }else{
            struct cart* temp = cart;
            while(temp != NULL){//show cart
                int qty = temp->quantity;
                double price = temp->row->price * qty;
                total_price += price;
                printf("%d product:%s\n",i,temp->row->product);
                printf("  price(per qty): %.1f\n",temp->row->price);//space to align
                printf("  price(total): %.1f\n",price);
                printf("  quantity: %d\n",qty);
                printf("<------------------------>\n");
                temp = temp->next;
                i++;
            }
            printf("\n<------------------------>\n");
            printf("Total price: $%.1f\n",total_price);
            printf("<------------------------>\n");

            printf("\n%d CHECKOUT\n",i);
            printf("%d Clear Cart\n",i+1);
        }
        do{
            printf("input the corresponding value for more action\n>");
            fflush_stdin();
            scanf("%d", &choice);
            if(choice >0 && choice < i){
                cart = cart_control(cart,choice);
            }else if(choice == i && cart != NULL){
                cart = checkout(cart);
            }else if(choice == i+1 && cart != NULL){
                cart = NULL;
                printf("Cart cleared\n");
            }
        }while(choice <0 || choice > i+1);
    }while(choice != 0);
    return cart;
}
struct cart* update_cart(struct cart* cart,int index);
struct cart* cart_control(struct cart* cart,int index){
    int choice = 0;
    struct inventory_row* row = Cartget(cart,index-1);
    int quantity = Cartqty(cart,index-1);
    do{
        char welcome[256];
        welcome_message(welcome);
        sprintf(welcome+strlen(welcome),"product: %s\n",row->product);
        sprintf(welcome+strlen(welcome),"price: %.1f\n",row->price);
        sprintf(welcome+strlen(welcome),"quantity: %d\n",quantity);
		choice = choices_selecter((char*[]){
            "remove",
        	"edit quantity"
        },2,welcome);

            if(choice == 1){
                cart = Cartremove(cart,index-1);
                printf("Remove successful\n");
                printf("press any key to continue\n");
                fflush_stdin();
                getchar();
            }else if(choice == 2){
                cart = update_cart(cart,index);
                printf("Update successful\n");
                printf("press any key to continue");
                fflush_stdin();
                getchar();
            }
    }while(choice != 1 || choice != 2 || choice !=3 );
    return cart;
}

struct cart* update_cart(struct cart* cart,int index){
    Cls();
    welcome_message(stdout);
    char choice;
    do{
        int quantity = 0;
        printf("enter the new quantity: ");
        fflush_stdin();
        scanf("%d", &quantity);
        printf("Are you sure you want to update this item?(y/n/e to exit)");
        fflush_stdin();
        scanf("%c", &choice);
        if(choice == 'y'){
            
            if(quantity != 0){
                cart = Cartupdate(cart,index-1,quantity);
            }else if (quantity == 0){
                cart = Cartremove(cart,index-1);
            }
        }
    }while(choice != 'y' && choice != 'e');
    return cart;
}



//Checkout

struct cart* checkout(struct cart* cart){
    Cls();
    welcome_message(stdout);
    
    long user_id = 0;
    printf("Please tap your card(student card, staff card,etc)(or input the id)(0 to cancel)\n>");
    scanf("%ld", &user_id);
    if(user_id == 0){
        printf("cancelled\n");
        printf("press any key to continue\n");
        fflush_stdin();
        getchar();
        return cart;
    }
    struct user_row* user = get_user(user_id);


    if(user == NULL){
        printf("Fail to indentify your card or error occurs\n");
        printf("press any key to continue\n");
        fflush_stdin();
        getchar();
        return cart;
    }else{
        printf("Welcome %s(%s)\n",user->name,user->role);
        printf("Are you sure you want to checkout?(y/n)\n>");
        char choice;
        fflush_stdin();
        scanf("%c", &choice);
        if(choice == 'y'){
            if(update_stock_N_checkout(cart,user)){//catch err
                printf("Checkout successful\n");
                printf("press any key to continue\n");
                fflush_stdin();
                getchar();
                return NULL;
            }else{
                printf("Checkout failed(files maybe corrputed)\n");
                printf("press any key to continue\n");
                fflush_stdin();
                getchar();
                return cart;
            }
        }else{
            printf("cancelled\n");
            printf("press any key to continue\n");
            fflush_stdin();
            getchar();
            return cart;
        }
    }


    return cart;
}
