#include <stdarg.h>
#include "print.h"
#include "vga.h"


const static size_t NUM_COLS = 80;
const static size_t NUM_ROWS = 25;

struct Char {
    uint8_t character;
    uint8_t color;
};




struct Char* buffer = (struct Char*) 0xb8000;
size_t col = 0;
size_t row = 0;
uint8_t color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4;

void clear_row(size_t row) {
    struct Char empty = (struct Char) {
        character: ' ',
        color: color,
    };

    for (size_t col = 0; col < NUM_COLS; col++) {
        buffer[col + NUM_COLS * row] = empty;
    }
}

void print_clear() {
    for (size_t i = 0; i < NUM_ROWS; i++) {
        clear_row(i);
    }
}

//void print_newline() {
//    col = 0;
//
//    if (row < NUM_ROWS - 1) {
//        row++;
//        return;
//    }
//
//    for (size_t row = 1; row < NUM_ROWS; row++) {
//        for (size_t col = 0; col < NUM_COLS; col++) {
//            struct Char character = buffer[col + NUM_COLS * row];
//            buffer[col + NUM_COLS * (row - 1)] = character;
//        }
//    }
//
//    clear_row(NUM_COLS - 1);
//}

void print_newline() {
    row++;
    col = 0;
    
    // Check for scrolling
    if (row >= NUM_ROWS) {
        row = NUM_ROWS - 1;
        // Scroll the screen up
        // Copy lines up
        // Clear the last line
    }
}

CursorPosition get_print_cursor_pos() {
    CursorPosition pos;
    pos.x = col; // Use col for x
    pos.y = row; // Use row for y

    return pos;
}


void print_hex(unsigned int num) {
    char buffer[9];  // Buffer to hold the hexadecimal string representation
    int i = 0;

    // Handle zero case
    if (num == 0) {
        print_char('0');
        return;
    }

    // Convert integer to hexadecimal in reverse order
    while (num > 0) {
        int digit = num % 16;
        if (digit < 10) {
            buffer[i++] = digit + '0';
        } else {
            buffer[i++] = (digit - 10) + 'A';
        }
        num /= 16;
    }

    // Print the hexadecimal number in correct order
    for (int j = i - 1; j >= 0; j--) {
        print_char(buffer[j]);
    }
}

void move_print_cursor(int x, int y) {
    col = x;
    row = y;
    set_cursor_position(col, row); // Move cursor to new position
}


void offset_print_cursor(int x, int y) {
    col += x;
    row += y;
    set_cursor_position(col, row);
}

// Function to print a single character
void print_char(char character) {
    if (character == '\n') {
        print_newline();
        return;
    }

    // Handle wrapping
    if (col >= NUM_COLS) {
        print_newline();
    }

    // Update the buffer
    buffer[col + NUM_COLS * row] = (struct Char) {
        .character = (uint8_t) character,
        .color = color,
    };

    col++;
}

// Function to print a string
void print_str(char* str) {
    size_t i = 0;
    while (str[i] != '\0') {
        print_char(str[i]);
        i++;
    }
}

void print_set_color(uint8_t foreground, uint8_t background) {
    color = foreground + (background << 4);
}


void print_int(int num) {
    // Handle negative numbers
    if (num < 0) {
        print_char('-');
        num = -num;
    }

    // Convert number to string
    char buffer[11];  // Buffer to hold integer string representation
    int i = 0;

    if (num == 0) {
        buffer[i++] = '0';
    } else {
        while (num > 0) {
            buffer[i++] = (num % 10) + '0';
            num /= 10;
        }
    }

    // Print the integer in correct order
    for (int j = i - 1; j >= 0; j--) {
        print_char(buffer[j]);
    }
}

#include <stdarg.h>
#include "print.h"

void print_formatted(const char* format, va_list args) {
    while (*format) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 's': {
                    char* str = va_arg(args, char*);
                    print_str(str);
                    break;
                }
                case 'x': {
                    unsigned int num = va_arg(args, unsigned int);
                    print_hex(num);
                    break;
                }
                case 'd': {
                    int num = va_arg(args, int);
                    print_int(num);
                    break;
                }
                case 'c': {
                    char ch = (char) va_arg(args, int); // Promoted to int
                    print_char(ch);
                    break;
                }
                case 'u': {
                    unsigned int num = va_arg(args, unsigned int);
                    print_uint(num); // Custom function for unsigned int
                    break;
                }
                case 'p': {
                    void* ptr = va_arg(args, void*);
                    print_pointer(ptr); // Custom function for pointers
                    break;
                }
                case 'f': {
                    double num = va_arg(args, double);
                    print_float(num); // Custom function for floating-point numbers
                    break;
                }
                default:
                    print_char('%');
                    print_char(*format);
                    break;
            }
        } else {
            print_char(*format);
        }
        format++;
    }
}
void print_uint(unsigned int num) {
    // Convert to string and print (implementation required)
    char buffer[11]; // Enough for 32-bit unsigned int
    int i = 0;
    if (num == 0) {
        print_char('0');
        return;
    }
    while (num > 0) {
        buffer[i++] = '0' + (num % 10);
        num /= 10;
    }
    while (i > 0) {
        print_char(buffer[--i]);
    }
}
void print_pointer(void* ptr) {
    unsigned long num = (unsigned long) ptr;
    print_str("0x");
    print_hex(num); // Assuming print_hex handles long
}
void print_float(double num) {
    // Simple implementation of floating-point printing
    int int_part = (int)num;
    int frac_part = (int)((num - int_part) * 1000000); // Six decimal places

    print_int(int_part);
    print_char('.');

    // Ensure fractional part is always printed with six digits
    for (int i = 0; i < 6; i++) {
        print_char('0' + (frac_part % 10));
        frac_part /= 10;
    }
}

void sscanf(const char *str, const char *format, char *filename, char *content) {
    const char *p = str;
    char *f = filename;
    char *c = content;
    
    while (*format) {
        if (*format == '%') {
            format++;
            if (*format == 's') {
                // Copy the first string
                while (*p && *p != ' ' && (f - filename) < MAX_STRING_LENGTH - 1) {
                    *f++ = *p++;
                }
                *f = '\0';
                
                // Skip any whitespace
                while (*p == ' ') p++;
                
                // Copy the second string
                while (*p && (c - content) < MAX_STRING_LENGTH - 1) {
                    *c++ = *p++;
                }
                *c = '\0';
            }
        }
        format++;
    }
}

int my_sscanf(const char *input, const char *format, char *output) {
    const char *in_ptr = input;
    const char *fmt_ptr = format;
    char *out_ptr = output;
    int match_count = 0;

    // Skip any leading whitespace in the input
    while (*in_ptr && (*in_ptr == ' ' || *in_ptr == '\t')) {
        in_ptr++;
    }

    // Process the format string
    while (*fmt_ptr) {
        if (*fmt_ptr == '%' && *(fmt_ptr + 1) == 's') {
            // Found a string specifier
            fmt_ptr += 2; // Skip %s

            // Copy input string to output until whitespace or end of input
            while (*in_ptr && *in_ptr != ' ' && *in_ptr != '\t' && *in_ptr != '\n') {
                *out_ptr++ = *in_ptr++;
            }
            *out_ptr = '\0'; // Null-terminate the output string
            match_count++;
        } else {
            // Match literal characters in format string
            if (*fmt_ptr == *in_ptr) {
                fmt_ptr++;
                in_ptr++;
            } else {
                // Literal character mismatch
                return match_count;
            }
        }
    }

    return match_count;
}

snprintf(char* buffer, size_t size, const char* format, ...) {
    va_list args;
    va_start(args, format);

    const char* traverse = format;
    size_t written = 0;

    while (*traverse && written < size - 1) {
        if (*traverse == '%' && *(traverse + 1)) {
            traverse++;
            if (*traverse == 's') {
                const char* str = va_arg(args, const char*);
                while (*str && written < size - 1) {
                    buffer[written++] = *str++;
                }
            } else if (*traverse == 'd') {
                int num = va_arg(args, int);
                char num_buffer[16];
                int num_len = 0;
                if (num < 0) {
                    if (written < size - 1) buffer[written++] = '-';
                    num = -num;
                }
                do {
                    num_buffer[num_len++] = '0' + (num % 10);
                    num /= 10;
                } while (num > 0);
                while (num_len > 0 && written < size - 1) {
                    buffer[written++] = num_buffer[--num_len];
                }
            }
        } else {
            buffer[written++] = *traverse;
        }
        traverse++;
    }

    buffer[written] = '\0';
    va_end(args);
    return written;
}


void printf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    print_formatted(format, args);
    va_end(args);
}
