#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"

// Current working directory 
char current_directory[MAX_PATH] = {0};

// Initialize the current directory
void InitializeDirectory() {
    GetCurrentDirectoryA(MAX_PATH, current_directory);
}

// Normalize path with proper backslashes
void NormalizePath(char* path) {
    size_t path_len = strlen(path);
    
    // Replace forward slashes with backslashes
    for (size_t i = 0; i < path_len; i++) {
        if (path[i] == '/') {
            path[i] = '\\';
        }
    }
    
    // Remove trailing backslash if present (except for root paths like "C:\")
    if (path_len > 3 && path[path_len - 1] == '\\') {
        path[path_len - 1] = '\0';
    }
}

// Check if directory exists
int DirectoryExists(const char* path) {
    DWORD attributes = GetFileAttributesA(path);
    return (attributes != INVALID_FILE_ATTRIBUTES && 
            (attributes & FILE_ATTRIBUTE_DIRECTORY));
}

// Change directory function
int ChangeDirectory(const char* path) {
    char target_path[MAX_PATH] = {0};
    
    // Handle "../" - needs special handling to remove trailing "/.."
    if (strcmp(path, "..") == 0 || strcmp(path, "../") == 0) {
        // Copy current path to work with
        strncpy(target_path, current_directory, MAX_PATH - 1);
        
        // Find the last backslash
        char* last_backslash = strrchr(target_path, '\\');
        
        // Don't go up from drive root (e.g., C:\)
        if (last_backslash > target_path + 2) {
            *last_backslash = '\0';  // Remove last directory component
        } else {
            // Keep drive letter root (e.g., "C:\")
            *(last_backslash + 1) = '\0';
        }
    }
    // Handle absolute path
    else if (strlen(path) >= 2 && path[1] == ':') {
        strncpy(target_path, path, MAX_PATH - 1);
        NormalizePath(target_path);
    }
    // Handle current directory
    else if (strcmp(path, ".") == 0 || strlen(path) == 0) {
        return 1; // No change needed
    }
    // Handle relative path
    else {
        size_t current_len = strlen(current_directory);
        if (current_directory[current_len - 1] == '\\') {
            snprintf(target_path, MAX_PATH, "%s%s", current_directory, path);
        } else {
            snprintf(target_path, MAX_PATH, "%s\\%s", current_directory, path);
        }
        NormalizePath(target_path);
    }
    
    // Check if directory exists and is accessible
    if (DirectoryExists(target_path)) {
        strncpy(current_directory, target_path, MAX_PATH - 1);
        return SetCurrentDirectoryA(target_path);
    }
    
    return 0;
}

// List directory contents - without buffer size parameter
void ListDirectory(char result[]) {
    char search_path[MAX_PATH];
    WIN32_FIND_DATAA find_data;
    char buffer[STANDARD_BUFF];
    
    // Initialize result buffer as empty
    result[0] = '\0';
    size_t used_size = 0;
    
    snprintf(search_path, sizeof(search_path), "%s\\*", current_directory);
    HANDLE h_find = FindFirstFileA(search_path, &find_data);
    
    if (h_find != INVALID_HANDLE_VALUE) {
        // Add directory header
        int header_len = snprintf(buffer, sizeof(buffer), "Directory listing for %s:\n", current_directory);
        
        // Check if we have enough space in the result buffer
        if (header_len < STANDARD_BUFF - used_size) {
            strcat(result, buffer);
            used_size += header_len;
        } else {
            strncpy(result, "Buffer too small", STANDARD_BUFF - 1);
            result[STANDARD_BUFF - 1] = '\0';
            FindClose(h_find);
            return;
        }
        
        do {
            int is_directory = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
            int line_len;
            
            if (is_directory) {
                line_len = snprintf(buffer, sizeof(buffer), "[DIR] %s\n", find_data.cFileName);
            } else {
                // Format with file size
                ULONGLONG file_size = ((ULONGLONG)find_data.nFileSizeHigh << 32) + find_data.nFileSizeLow;
                line_len = snprintf(buffer, sizeof(buffer), "%s (%llu bytes)\n", find_data.cFileName, file_size);
            }
            
            // Check if we have enough space for this line
            if (used_size + line_len < STANDARD_BUFF) {
                strcat(result, buffer);
                used_size += line_len;
            } else {
                // Indicate truncation and break the loop
                strcat(result, "\n[Directory listing truncated due to buffer size limitation]");
                break;
            }
            
        } while (FindNextFileA(h_find, &find_data));

        FindClose(h_find);
    } else {
        snprintf(result, STANDARD_BUFF, "Error accessing directory %s\n", current_directory);
    }
}

// Get current directory - without buffer size parameter
void GetCurrentWorkingDir(char result[]) {
    strncpy(result, current_directory, STANDARD_BUFF - 1);
    result[STANDARD_BUFF - 1] = '\0';
}

// Main handler for directory commands - without buffer size parameter
void HandleDirectoryCommand(char result[], char* command, char* args) {
    // Initialize directory if not done yet
    if (strlen(current_directory) == 0) {
        InitializeDirectory();
    }
    
    if (strcmp(command, "cd") == 0) {
        if (ChangeDirectory(args)) {
            snprintf(result, STANDARD_BUFF, "Changed directory to: %s", current_directory);
        } else {
            snprintf(result, STANDARD_BUFF, "Error: Could not change to directory: %s", args);
        }
    }
    else if (strcmp(command, "pwd") == 0) {
        GetCurrentWorkingDir(result);
    }
    else if (strcmp(command, "ls") == 0 || strcmp(command, "dir") == 0) {
        ListDirectory(result);
    }
    else {
        snprintf(result, STANDARD_BUFF, "Unknown directory command: %s", command);
    }
}