#pragma once

#include <Arduino.h>
#include <esp_camera.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <vector>

class StorageSD
{
public:
  enum class Result
  {
    Ok,
    Busy,
    Unavailable,
    InvalidPath,
    NotFound,
    TooLarge,
    OutOfMemory,
    ReadError
  };

  class PhotoBuffer final
  {
  public:
    PhotoBuffer() = default;
    ~PhotoBuffer();
    PhotoBuffer(const PhotoBuffer &) = delete;
    PhotoBuffer &operator=(const PhotoBuffer &) = delete;
    PhotoBuffer(PhotoBuffer &&other) noexcept;
    PhotoBuffer &operator=(PhotoBuffer &&other) noexcept;

    const uint8_t *data() const { return buffer; }
    size_t size() const { return length; }
    bool empty() const { return buffer == nullptr; }
    void reset();

  private:
    friend class StorageSD;
    uint8_t *buffer = nullptr;
    size_t length = 0;
  };

  bool begin();
  bool saveNextJpeg(
      camera_fb_t *frame,
      char *savedFilename,
      size_t savedFilenameSize);
  Result listPhotoNumbers(
      std::vector<uint32_t> &photoNumbers,
      size_t maximumCount);
  Result loadPhoto(
      const char *path,
      PhotoBuffer &photo,
      size_t maximumSizeBytes);
  static bool parsePhotoPath(const char *path, uint32_t &photoNumber);

private:
  SemaphoreHandle_t storageMutex = nullptr;
  uint32_t nextPhotoNumber = 1;
  bool photoNumberReady = false;

  bool removeOrphanedTempFilesUnlocked();
  bool initializeNextPhotoNumberUnlocked();
  bool saveJpegUnlocked(
      camera_fb_t *frame,
      const char *temporaryFilename,
      const char *finalFilename);
  bool validateJpegFileUnlocked(const char *filename, size_t expectedSize);
};
