/**
 * @file sdcard.hpp
 * @brief SD Card driver for ESP32 using SPI interface
 * @details Ported from Arduino SD library to use ESP-IDF SPI driver
 * 
 * This driver implements SD card functionality using ESP-IDF's SPI master
 * driver while maintaining the file system logic from the Arduino SD library.
 * 
 * @author Mahmoud Elmohtady
 * @company Nabd solutions - ASF
 * @copyright Copyright (c) 2025
 */

#pragma once

#include <stdint.h>
#include <stdbool.h>
#include "driver/spi_master.h"
#include "driver/gpio.h"

// File open modes (compatible with Arduino SD library)
#define SD_FILE_READ    0x01
#define SD_FILE_WRITE   0x02

// SD card types
#define SD_CARD_TYPE_SD1    1  // Standard capacity V1 SD card
#define SD_CARD_TYPE_SD2    2  // Standard capacity V2 SD card
#define SD_CARD_TYPE_SDHC   3  // High Capacity SD card

/**
 * @class SdCardDriver
 * @brief High-level SD card driver interface
 */
class SdCardDriver {
public:
    /**
     * @brief Constructor
     */
    SdCardDriver();

    /**
     * @brief Destructor
     */
    ~SdCardDriver();

    /**
     * @brief Mount SD card on SPI bus
     * @param mount_point Mount point path (e.g., "/ESP")
     * @param spi_host SPI host device (e.g., SPI3_HOST)
     * @param cs_pin Chip select GPIO pin number
     * @return true if mount successful, false otherwise
     */
    bool mount(const char* mount_point, spi_host_device_t spi_host, uint8_t cs_pin);

    /**
     * @brief Unmount SD card
     */
    void unmount();

    /**
     * @brief Check if SD card is mounted
     * @return true if mounted, false otherwise
     */
    bool isMounted() const { return m_mounted; }

    /**
     * @brief Get card type
     * @return Card type (SD_CARD_TYPE_SD1, SD_CARD_TYPE_SD2, SD_CARD_TYPE_SDHC)
     */
    uint8_t getCardType() const;

    /**
     * @brief Get card size in bytes
     * @return Card size in bytes (0 if error)
     */
    uint64_t getCardSize() const;

    // File operations
    /**
     * @brief Open a file
     * @param filepath Path to file
     * @param mode Open mode (SD_FILE_READ or SD_FILE_WRITE)
     * @return File descriptor (negative if error)
     */
    int open(const char* filepath, uint8_t mode);

    /**
     * @brief Close a file
     * @param fd File descriptor
     * @return true if successful, false otherwise
     */
    bool close(int fd);

    /**
     * @brief Write data to file
     * @param fd File descriptor
     * @param data Data buffer
     * @param size Number of bytes to write
     * @return Number of bytes written (negative if error)
     */
    int write(int fd, const void* data, size_t size);

    /**
     * @brief Read data from file
     * @param fd File descriptor
     * @param buffer Buffer to read into
     * @param size Number of bytes to read
     * @return Number of bytes read (negative if error)
     */
    int read(int fd, void* buffer, size_t size);

    /**
     * @brief Check if file exists
     * @param filepath Path to file
     * @return true if exists, false otherwise
     */
    bool exists(const char* filepath);

    /**
     * @brief Create directory
     * @param dirpath Path to directory
     * @return true if successful, false otherwise
     */
    bool mkdir(const char* dirpath);

    /**
     * @brief Remove file
     * @param filepath Path to file
     * @return true if successful, false otherwise
     */
    bool remove(const char* filepath);

    /**
     * @brief Remove directory
     * @param dirpath Path to directory
     * @return true if successful, false otherwise
     */
    bool rmdir(const char* dirpath);

private:
    // Forward declarations of internal classes
    class Sd2Card;
    class SdVolume;
    class SdFile;

    // Member variables
    bool m_mounted;
    char m_mountPoint[32];
    spi_host_device_t m_spiHost;
    uint8_t m_csPin;
    spi_device_handle_t m_spiDevice;

    // Internal driver components
    Sd2Card* m_card;
    SdVolume* m_volume;
    
    // Helper methods
    bool initializeSpi();
    void deinitializeSpi();
};

