#ifndef NOMINMAX
#define NOMINMAX 1
#endif

#include "core/preview_shared_memory.hpp"

#include <algorithm>
#include <array>
#include <cstring>
#include <limits>

#ifdef _WIN32
#include <windows.h>
#endif

namespace smartcut::core {
namespace {

constexpr std::uint32_t preview_magic = 0x36504353U;  // SCP6
constexpr std::uint32_t preview_version = 1;
constexpr std::size_t maximum_preview_bytes = 1024U * 1024U * 1024U;

struct SharedPreviewHeader {
  std::uint32_t magic{};
  std::uint32_t version{};
  std::uint32_t header_bytes{};
  std::uint32_t total_bytes{};
  volatile long acknowledged{};
  std::uint32_t reserved{};
  std::uint64_t sequence{};
  std::uint64_t frame_index{};
  std::uint64_t pixel_bytes{};
  std::int32_t width{};
  std::int32_t height{};
  std::int32_t stride{};
  std::int32_t pixel_format{-1};
  std::uint8_t tone_mapped{};
  std::array<std::uint8_t, 7> padding{};
  std::array<char, 48> display_color_mode{};
};

#ifdef _WIN32
std::wstring wide(std::string_view text) {
  if (text.empty()) return {};
  const auto size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text.data(), static_cast<int>(text.size()), nullptr, 0);
  if (size <= 0) return {};
  std::wstring result(static_cast<std::size_t>(size), L'\0');
  if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text.data(), static_cast<int>(text.size()), result.data(), size) != size) return {};
  return result;
}

std::wstring mapping_path(std::string_view name) {
  auto result = wide(name); if (result.empty()) return {}; constexpr std::wstring_view prefix = L"Local\\"; if (!result.starts_with(prefix)) result = std::wstring(prefix) + result; return result;
}

bool valid_header(const SharedPreviewHeader& header, std::size_t mapped_bytes) {
  return header.magic == preview_magic && header.version == preview_version &&
         header.header_bytes == sizeof(SharedPreviewHeader) && header.total_bytes <= mapped_bytes &&
         header.pixel_bytes <= maximum_preview_bytes &&
         header.pixel_bytes + sizeof(SharedPreviewHeader) == header.total_bytes &&
         header.width > 0 && header.height > 0 && header.stride > 0;
}
#endif

}  // namespace

struct SharedPreviewPublisher::Impl {
#ifdef _WIN32
  HANDLE mapping{nullptr};
  void* view{};
#endif
  std::uint64_t sequence{};
  ~Impl() {
#ifdef _WIN32
    if (view) UnmapViewOfFile(view);
    if (mapping) CloseHandle(mapping);
#endif
  }
};

SharedPreviewPublisher::SharedPreviewPublisher() = default;
SharedPreviewPublisher::SharedPreviewPublisher(std::unique_ptr<Impl> implementation) : implementation_(std::move(implementation)) {}
SharedPreviewPublisher::~SharedPreviewPublisher() = default;
SharedPreviewPublisher::SharedPreviewPublisher(SharedPreviewPublisher&&) noexcept = default;
SharedPreviewPublisher& SharedPreviewPublisher::operator=(SharedPreviewPublisher&&) noexcept = default;

std::optional<SharedPreviewPublisher> SharedPreviewPublisher::publish(std::string_view mapping_name,
                                                                     const PreviewFrame& frame) {
#ifdef _WIN32
  if (frame.pixels.empty() || frame.pixels.size() > maximum_preview_bytes || frame.width <= 0 || frame.height <= 0 || frame.stride <= 0) return std::nullopt;
  const auto name = mapping_path(mapping_name); if (name.empty()) return std::nullopt; const auto total = sizeof(SharedPreviewHeader) + frame.pixels.size(); if (total > std::numeric_limits<std::uint32_t>::max()) return std::nullopt;
  const auto high = static_cast<DWORD>(static_cast<std::uint64_t>(total) >> 32U); const auto low = static_cast<DWORD>(total); const HANDLE mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, high, low, name.c_str()); if (!mapping || GetLastError() == ERROR_ALREADY_EXISTS) { if (mapping) CloseHandle(mapping); return std::nullopt; }
  void* view = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, total); if (!view) { CloseHandle(mapping); return std::nullopt; }
  auto* header = static_cast<SharedPreviewHeader*>(view); *header = {}; header->magic = preview_magic; header->version = preview_version; header->header_bytes = sizeof(SharedPreviewHeader); header->total_bytes = static_cast<std::uint32_t>(total); header->sequence = frame.sequence; header->frame_index = frame.frame_index; header->pixel_bytes = frame.pixels.size(); header->width = frame.width; header->height = frame.height; header->stride = frame.stride; header->pixel_format = frame.pixel_format; header->tone_mapped = frame.tone_mapped ? 1 : 0; const auto color_bytes = std::min(frame.display_color_mode.size(), header->display_color_mode.size() - 1); std::memcpy(header->display_color_mode.data(), frame.display_color_mode.data(), color_bytes); std::memcpy(static_cast<std::uint8_t*>(view) + sizeof(SharedPreviewHeader), frame.pixels.data(), frame.pixels.size()); FlushViewOfFile(view, total);
  auto implementation = std::make_unique<Impl>(); implementation->mapping = mapping; implementation->view = view; implementation->sequence = frame.sequence; return SharedPreviewPublisher(std::move(implementation));
#else
  (void)mapping_name; (void)frame; return std::nullopt;
#endif
}

bool SharedPreviewPublisher::valid() const { return implementation_ != nullptr; }
bool SharedPreviewPublisher::acknowledged() const {
#ifdef _WIN32
  return implementation_ && implementation_->view && static_cast<const SharedPreviewHeader*>(implementation_->view)->acknowledged != 0;
#else
  return false;
#endif
}
std::uint64_t SharedPreviewPublisher::sequence() const { return implementation_ ? implementation_->sequence : 0; }

std::shared_ptr<PreviewFrame> acquire_shared_preview(std::string_view mapping_name) {
#ifdef _WIN32
  const auto name = mapping_path(mapping_name); if (name.empty()) return {}; const HANDLE mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, name.c_str()); if (!mapping) return {}; void* view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); if (!view) { CloseHandle(mapping); return {}; }
  const auto* header = static_cast<const SharedPreviewHeader*>(view); MEMORY_BASIC_INFORMATION region{}; const auto queried = VirtualQuery(view, &region, sizeof(region)); const auto mapped = queried == sizeof(region) ? region.RegionSize : 0; if (!valid_header(*header, mapped)) { UnmapViewOfFile(view); CloseHandle(mapping); return {}; }
  auto frame = std::make_shared<PreviewFrame>(); frame->sequence = header->sequence; frame->frame_index = header->frame_index; frame->width = header->width; frame->height = header->height; frame->stride = header->stride; frame->pixel_format = header->pixel_format; frame->tone_mapped = header->tone_mapped != 0; const auto color_end = std::find(header->display_color_mode.cbegin(), header->display_color_mode.cend(), '\0'); frame->display_color_mode.assign(header->display_color_mode.cbegin(), color_end); const auto* pixels = static_cast<const std::uint8_t*>(view) + sizeof(SharedPreviewHeader); frame->pixels.assign(pixels, pixels + header->pixel_bytes); UnmapViewOfFile(view); CloseHandle(mapping); return frame;
#else
  (void)mapping_name; return {};
#endif
}

bool acknowledge_shared_preview(std::string_view mapping_name, std::uint64_t sequence) {
#ifdef _WIN32
  const auto name = mapping_path(mapping_name); if (name.empty()) return false; const HANDLE mapping = OpenFileMappingW(FILE_MAP_WRITE | FILE_MAP_READ, FALSE, name.c_str()); if (!mapping) return false; void* view = MapViewOfFile(mapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, sizeof(SharedPreviewHeader)); if (!view) { CloseHandle(mapping); return false; } auto* header = static_cast<SharedPreviewHeader*>(view); const bool matches = header->magic == preview_magic && header->version == preview_version && header->sequence == sequence; if (matches) InterlockedExchange(&header->acknowledged, 1); UnmapViewOfFile(view); CloseHandle(mapping); return matches;
#else
  (void)mapping_name; (void)sequence; return false;
#endif
}

}  // namespace smartcut::core
