#pragma once


//Includes 
#include <Arduino.h>
#include <esp_camera.h>
#include <esp_timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <freertos/task.h>

#include "pinsdef.h"

// Wybierz jeden z trzech profili jakości zdjęć.
#define PHOTO_QUALITY_LOW 1
#define PHOTO_QUALITY_MEDIUM 2
#define PHOTO_QUALITY_HIGH 3

#ifndef PHOTO_QUALITY
#define PHOTO_QUALITY PHOTO_QUALITY_HIGH
#endif

#if PHOTO_QUALITY != PHOTO_QUALITY_LOW && \
    PHOTO_QUALITY != PHOTO_QUALITY_MEDIUM && \
    PHOTO_QUALITY != PHOTO_QUALITY_HIGH
#error "PHOTO_QUALITY must be PHOTO_QUALITY_LOW, PHOTO_QUALITY_MEDIUM or PHOTO_QUALITY_HIGH"
#endif

class CameraApp {
public:
  bool begin();
  int configButtonAndFlash();
  camera_fb_t* captureWithFlash();
  void release(camera_fb_t* frame);
  void blinkFlash(uint8_t count, uint16_t onTimeMs = 100,
                  uint16_t offTimeMs = 100);

private:
  struct CaptureRequest {
    uint32_t id;
    int64_t earliestAcceptedTimestampUs;
    int64_t deadlineTimestampUs;
  };

  struct CaptureResult {
    uint32_t id;
    camera_fb_t *frame;
  };

  camera_config_t config{};
  QueueHandle_t captureRequestQueue = nullptr;
  QueueHandle_t captureResultQueue = nullptr;
  SemaphoreHandle_t captureWorkerAvailable = nullptr;
  TaskHandle_t captureWorkerTask = nullptr;
  esp_timer_handle_t flashSafetyTimer = nullptr;
  uint32_t nextCaptureRequestId = 0;

  bool startCaptureWorker();
  void discardPendingCaptureResults();
  void captureWorkerLoop();
  static void captureWorkerEntry(void *parameter);
  static void flashSafetyTimerCallback(void *parameter);
  bool flashOn();
  void flashOff();
  void forceFlashOff();
};
