#include <fstream>
#include <filesystem>
#include <algorithm>
#include <array>
#include <chrono>
#include <charconv>
#include <iostream>
#include <iterator>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
#include <cstddef>
#include <clocale>
#include "core/build_info.hpp"
#include "core/entitlement.hpp"
#include "core/source_identity.hpp"
#include "core/windows_utf8_argv.hpp"
#include "core/control_ipc.hpp"
#include "core/project_model.hpp"
#include "core/render_plan.hpp"
#include "core/render_report.hpp"
#include "media/access_unit_index.hpp"
#include "media/index_cache.hpp"
#include "media/video_frame_index.hpp"
#include "media/stream_probe.hpp"
#include "media/frame_decode.hpp"
#include "media/preview_conversion.hpp"
#include "media/audio_timing.hpp"
#include "media/audio_playback.hpp"
#include "media/multitrack_fixture.hpp"
#include "media/mkv_timed_range.hpp"
#include "media/mkv_copy.hpp"
#include "media/boundary_encode.hpp"
#include "media/boundary_fixture.hpp"
#include "core/preview_sync.hpp"
#include "media/nal_inventory.hpp"
#include "media/ffmpeg_inventory.hpp"
#include "media/mkv_roundtrip.hpp"
#include "media/rpu_injector.hpp"

namespace {
template <typename Integer>
Integer checked_integer(std::string_view text, std::string_view field,
                        Integer minimum = std::numeric_limits<Integer>::lowest(),
                        Integer maximum = (std::numeric_limits<Integer>::max)()) {
  static_assert(std::is_integral_v<Integer>);
  Integer value{};
  const auto [end, error] = std::from_chars(text.data(), text.data() + text.size(), value);
  if (text.empty() || error != std::errc{} || end != text.data() + text.size() ||
      value < minimum || value > maximum) {
    throw std::invalid_argument(std::string(field) + " must be a complete in-range integer");
  }
  return value;
}

std::size_t checked_size(std::string_view text, std::string_view field = "numeric argument") {
  return checked_integer<std::size_t>(text, field);
}

std::uint64_t checked_u64(std::string_view text, std::string_view field = "numeric argument") {
  return checked_integer<std::uint64_t>(text, field);
}

std::int64_t checked_i64(std::string_view text, std::string_view field = "numeric argument") {
  return checked_integer<std::int64_t>(text, field);
}

const smartcut::core::EntitlementResult& delivery_entitlement() {
  static const auto result = [] {
#ifdef SMARTCUT_INTERNAL_TEST_CLI
    smartcut::core::EntitlementResult entitlement;
    entitlement.state = smartcut::core::EntitlementState::paid;
    entitlement.detail = "Internal non-packaged test CLI";
    return entitlement;
#else
    const auto now = std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
    return smartcut::core::verify_installed_entitlement(now);
#endif
  }();
  return result;
}

bool clean_video_delivery_command(int argc, char** argv) {
  if (argc < 2) return false;
  constexpr std::array<std::string_view, 14> commands{
      "copy-mkv-timed-range", "make-performance-fixture", "make-ad-fixture",
      "make-boundary-fixture", "make-multitrack-fixture", "make-dvd-subtitle-fixture",
      "extract-hevc", "copy-mkv", "copy-mkv-range", "encode-boundary",
      "join-mkv", "mux-mkv", "export-mkv", "export-range-mkv"};
  const std::string_view command(argv[1]);
  if (command == "metadata-lab") {
    for (int index = 2; index < argc; ++index)
      if (std::string_view(argv[index]) == "--inject-rpu" ||
          std::string_view(argv[index]) == "--generate-mkv") return true;
  }
  return std::find(commands.begin(), commands.end(), command) != commands.end();
}

int reject_evaluation_clean_delivery(std::string_view operation) {
  std::cout << "{\"schema\":\"cli-entitlement-v1\",\"status\":\"BLOCKED\","
            << "\"edition\":\"evaluation\",\"operation\":\"" << operation
            << "\",\"entitlement_state\":\""
            << smartcut::core::entitlement_state_name(delivery_entitlement().state)
            << "\",\"reason\":\"A paid licence is required for CLI operations that create unwatermarked video; use Save Video in the GUI for a permanently watermarked evaluation export\"}\n";
  return 6;
}
}  // namespace

int metadata_lab(int argc, char** argv) {
  std::string input_path;
  std::string output_path;
  auto codec = smartcut::media::Codec::hevc;
  bool strict = false;
  bool container = false;
  std::size_t max_frames = 0;
  std::string generate_mkv;
  std::string rpu_path;
  for (int i = 2; i < argc; ++i) {
    const std::string_view arg = argv[i];
    if (arg == "--input" && i + 1 < argc) input_path = argv[++i];
    else if (arg == "--output" && i + 1 < argc) output_path = argv[++i];
    else if (arg == "--codec" && i + 1 < argc) {
      const std::string_view value = argv[++i];
      if (value == "h264") codec = smartcut::media::Codec::h264;
      else if (value != "hevc") { std::cerr << "unsupported codec\n"; return 2; }
    } else if (arg == "--strict") strict = true;
    else if (arg == "--container") container = true;
    else if (arg == "--max-frames" && i + 1 < argc) max_frames = checked_size(argv[++i], "--max-frames");
    else if (arg == "--generate-mkv" && i + 1 < argc) generate_mkv = argv[++i];
    else if (arg == "--inject-rpu" && i + 1 < argc) rpu_path = argv[++i];
    else { std::cerr << "unknown or incomplete option: " << arg << "\n"; return 2; }
  }
  if (!generate_mkv.empty()) { const int result = smartcut::media::write_main10_test_mkv(generate_mkv); if (result != 0) { std::cerr << "generate-mkv failed: " << result << "\n"; return 4; } std::cout << "generated " << generate_mkv << "\n"; return 0; }
  if (input_path.empty()) {
    std::cerr << "usage: smartcut-cli metadata-lab --input <annex-b-file> [--codec h264|hevc] [--output report.json] [--strict] [--container] [--max-frames N] [--generate-mkv output.mkv] [--inject-rpu raw_rpu.bin]\n";
    return 2;
  }
  std::ifstream input(input_path, std::ios::binary);
  if (!input) { std::cerr << "cannot open input: " << input_path << "\n"; return 2; }
  if (container) { const auto report = smartcut::media::inventory_container(input_path, max_frames).json; if (output_path.empty()) std::cout << report << '\n'; else { std::ofstream output(output_path, std::ios::binary); if (!output) { std::cerr << "cannot write output: " << output_path << "\n"; return 2; } output << report << '\n'; } return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  const std::vector<std::uint8_t> bytes((std::istreambuf_iterator<char>(input)), {});
  if (!rpu_path.empty()) {
    if (output_path.empty()) { std::cerr << "--inject-rpu requires --output <annex-b-file>\n"; return 2; }
    std::ifstream rpu_input(rpu_path, std::ios::binary);
    if (!rpu_input) { std::cerr << "cannot open RPU: " << rpu_path << "\n"; return 2; }
    const std::vector<std::uint8_t> raw_rpu((std::istreambuf_iterator<char>(rpu_input)), {});
    const auto injected = smartcut::media::prepend_hevc_rpu(bytes, raw_rpu);
    std::ofstream output(output_path, std::ios::binary);
    if (!output) { std::cerr << "cannot write output: " << output_path << "\n"; return 2; }
    output.write(reinterpret_cast<const char*>(injected.data()), static_cast<std::streamsize>(injected.size()));
    const auto report = smartcut::media::to_json(smartcut::media::inventory_annex_b(smartcut::media::Codec::hevc, injected));
    std::cout << report << '\n';
    return 0;
  }
  const auto inventory = smartcut::media::inventory_annex_b(codec, bytes);
  bool has_parameter_set = false;
  bool has_random_access = false;
  for (const auto& unit : inventory.units) { has_parameter_set |= unit.parameter_set; has_random_access |= unit.random_access; }
  if (strict && (inventory.units.empty() || !has_parameter_set || !has_random_access)) {
    std::cerr << "strict metadata-lab validation failed: expected NAL units, parameter set, and random-access unit\n";
    return 3;
  }
  const auto report = smartcut::media::to_json(inventory);
  if (output_path.empty()) std::cout << report << '\n';
  else { std::ofstream output(output_path, std::ios::binary); if (!output) { std::cerr << "cannot write output: " << output_path << "\n"; return 2; } output << report << '\n'; }
  return 0;
}

int main(int argc, char** argv) {
  auto utf8_arguments = smartcut::core::windows_utf8_argv();
  if (!utf8_arguments.pointers.empty()) { argc = static_cast<int>(utf8_arguments.pointers.size()); argv = utf8_arguments.pointers.data(); }
  std::setlocale(LC_ALL, ".UTF-8");
  try {
  if (!delivery_entitlement().paid() && clean_video_delivery_command(argc, argv))
    return reject_evaluation_clean_delivery(argv[1]);

  if (argc == 4 && (std::string_view(argv[1]) == "ipc-ping" || std::string_view(argv[1]) == "ipc-shutdown") && std::string_view(argv[2]) == "--pipe") {
    const bool shutdown = std::string_view(argv[1]) == "ipc-shutdown"; const auto request = std::string{"{\"schema\":\"control-request-v1\",\"id\":1,\"command\":\""} + (shutdown ? "shutdown" : "ping") + "\"}"; const auto response = smartcut::core::request_control_pipe(argv[3], request); if (!response) { std::cerr << "control pipe request failed\n"; return 5; } std::cout << *response << '\n'; return response->find("\"ok\":true") != std::string::npos ? 0 : 5;
  }
  if (argc == 10 && std::string_view(argv[1]) == "make-performance-fixture" && std::string_view(argv[2]) == "--output" && std::string_view(argv[4]) == "--width" && std::string_view(argv[6]) == "--height" && std::string_view(argv[8]) == "--frames") {
    const auto width = checked_integer<int>(argv[5], "--width", 16, 16384);
    const auto height = checked_integer<int>(argv[7], "--height", 16, 16384);
    const auto frames = checked_integer<int>(argv[9], "--frames", 1, 1000000);
    const int result = smartcut::media::write_main10_test_mkv(argv[3], width, height, frames);
    std::cout << "{\"schema\":\"performance-fixture-v1\",\"status\":\"" << (result == 0 ? "PASSED" : "FAILED") << "\",\"result\":" << result << ",\"width\":" << width << ",\"height\":" << height << ",\"frames\":" << frames << "}\n";
    return result == 0 ? 0 : 5;
  }
  if (argc == 4 && std::string_view(argv[1]) == "make-ad-fixture" && std::string_view(argv[2]) == "--output") {
    const int result = smartcut::media::write_main10_test_mkv(argv[3], 160, 90, 60, true);
    std::cout << "{\"schema\":\"ad-fixture-v1\",\"status\":\"" << (result == 0 ? "PASSED" : "FAILED") << "\"}\n";
    return result == 0 ? 0 : 5;
  }
  if (argc == 4 && std::string_view(argv[1]) == "make-dolby-e-fixture" &&
      std::string_view(argv[2]) == "--output") {
    const auto report = smartcut::media::make_dolby_e_s337m_fixture(argv[3]);
    std::cout << report << '\n';
    return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc >= 4 && std::string_view(argv[1]) == "make-boundary-fixture" &&
      std::string_view(argv[2]) == "--output") {
    std::string codec{"hevc"};
    std::string pixel_format{"yuv420p10le"};
    std::string transfer{"bt709"};
    bool captions = false;
    for (int option = 4; option + 1 < argc; option += 2) {
      const std::string_view key(argv[option]);
      const std::string value(argv[option + 1]);
      if (key == "--codec") codec = value;
      else if (key == "--pixel-format") pixel_format = value;
      else if (key == "--transfer") transfer = value;
      else if (key == "--captions") captions = value == "yes" || value == "true" || value == "1";
      else return 2;
    }
    const int result = smartcut::media::write_boundary_format_fixture(
        argv[3], codec, pixel_format, transfer, captions);
    std::cout << "{\"schema\":\"boundary-format-fixture-v1\",\"status\":\""
              << (result == 0 ? "PASSED" : "FAILED") << "\",\"result\":" << result
              << ",\"codec\":\"" << codec << "\",\"pixel_format\":\"" << pixel_format
              << "\",\"transfer\":\"" << transfer << "\",\"captions\":"
              << (captions ? "true" : "false") << "}\n";
    return result == 0 ? 0 : 5;
  }
  if (argc == 4 && std::string_view(argv[1]) == "av-drift" && std::string_view(argv[2]) == "--input") {
    const auto report = smartcut::media::measure_av_drift(argv[3]);
    std::cout << report << '\n';
    return report.find("\"error\"") == std::string::npos ? 0 : 4;
  }
  if (argc == 10 && std::string_view(argv[1]) == "copy-mkv-timed-range" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-video-packet" && std::string_view(argv[8]) == "--end-video-packet") {
    const auto report = smartcut::media::copy_mkv_timed_range(
        argv[3], argv[5], checked_size(argv[7], "--first-video-packet"),
        checked_size(argv[9], "--end-video-packet"));
    std::cout << report << '\n';
    return report.find("\"error\"") == std::string::npos ? 0 : 4;
  }
  if (argc == 10 && std::string_view(argv[1]) == "validate-mkv-timed-range" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-video-packet" && std::string_view(argv[8]) == "--end-video-packet") {
    const auto report = smartcut::media::validate_mkv_timed_range(
        argv[3], argv[5], checked_size(argv[7], "--first-video-packet"),
        checked_size(argv[9], "--end-video-packet"));
    std::cout << report << '\n';
    return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc == 6 && std::string_view(argv[1]) == "make-multitrack-fixture" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") {
    const auto report = smartcut::media::make_mkv_multitrack_fixture(argv[3], argv[5]);
    std::cout << report << '\n';
    return report.find("\"error\"") == std::string::npos ? 0 : 4;
  }
  if (argc == 6 && std::string_view(argv[1]) == "make-dvd-subtitle-fixture" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") {
    const auto report = smartcut::media::make_mkv_dvd_subtitle_fixture(argv[3], argv[5]);
    std::cout << report << '\n';
    return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 4;
  }
  if (argc == 4 && std::string_view(argv[1]) == "dovi-config" && std::string_view(argv[2]) == "--input") {
    const auto report = smartcut::media::dovi_config_report(argv[3]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc == 4 && std::string_view(argv[1]) == "hdr10plus-sequence" && std::string_view(argv[2]) == "--input") {
    const auto report = smartcut::media::hdr10plus_sequence_report(argv[3]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc == 4 && std::string_view(argv[1]) == "dovi-rpu-sequence" && std::string_view(argv[2]) == "--input") {
    const auto report = smartcut::media::dovi_rpu_sequence_report(argv[3]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc == 6 && std::string_view(argv[1]) == "extract-hevc" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") {
    const bool extracted = smartcut::media::extract_hevc_annex_b(argv[3], argv[5]); std::cout << "{\"schema\":\"hevc-extract-v1\",\"status\":\"" << (extracted ? "PASSED" : "FAILED") << "\"}\n"; return extracted ? 0 : 5;
  }
  if ((argc == 4 || (argc == 6 && std::string_view(argv[4]) == "--max-frames")) && std::string_view(argv[1]) == "audio-pcm" && std::string_view(argv[2]) == "--input") {
    const auto max_frames = argc == 6 ? checked_size(argv[5], "--max-frames") : 0;
    const auto report = smartcut::media::audio_pcm_report(argv[3], max_frames); std::cout << report << '\n';
    return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc >= 4 && std::string_view(argv[1]) == "frame-index" && std::string_view(argv[2]) == "--input") {
    std::size_t stream = 0;
    std::filesystem::path cache;
    for (int i = 4; i < argc; i += 2) {
      if (i + 1 >= argc) { std::cerr << "incomplete frame-index option\n"; return 2; }
      if (std::string_view(argv[i]) == "--video-stream") stream = checked_size(argv[i + 1], "--video-stream");
      else if (std::string_view(argv[i]) == "--cache") cache = argv[i + 1];
      else { std::cerr << "usage: smartcut-cli frame-index --input <container> [--video-stream N] [--cache path]\n"; return 2; }
    }
    const auto report = cache.empty() ? smartcut::media::build_video_frame_index(argv[3], stream)
                                      : smartcut::media::load_or_build_video_frame_index(argv[3], stream, cache);
    std::cout << report << '\n';
    return report.find("\"error\"") == std::string::npos ? 0 : 5;
  }
  if (argc == 6 && std::string_view(argv[1]) == "seek-stress" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--iterations") {
    try { const auto report = smartcut::media::validate_random_seeks(argv[3], checked_size(argv[5], "--iterations")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
    catch (const std::exception& error) { std::cerr << "seek validation failed: " << error.what() << '\n'; return 5; }
  }
  if (argc == 6 && std::string_view(argv[1]) == "copy-mkv" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") { const auto report = smartcut::media::copy_mkv_packets(argv[3], argv[5]); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  if (argc == 10 && std::string_view(argv[1]) == "copy-mkv-range" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-video-packet" && std::string_view(argv[8]) == "--end-video-packet") {
    try { const auto report = smartcut::media::copy_mkv_timed_range(argv[3], argv[5], checked_size(argv[7], "--first-video-packet"), checked_size(argv[9], "--end-video-packet")); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
    catch (const std::exception& error) { std::cerr << "copy range failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 6 && std::string_view(argv[1]) == "validate-copy-mkv" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") { const auto report = smartcut::media::validate_mkv_copy(argv[3], argv[5]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 10 && std::string_view(argv[1]) == "encode-boundary" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-frame" && std::string_view(argv[8]) == "--end-frame") { try { const auto report = smartcut::media::encode_mkv_boundary(argv[3], argv[5], checked_u64(argv[7], "--first-frame"), checked_u64(argv[9], "--end-frame")); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; } catch (const std::exception& error) { std::cerr << "boundary encode failed: " << error.what() << '\n'; return 4; } }
  if (argc == 8 && std::string_view(argv[1]) == "validate-boundary" && std::string_view(argv[2]) == "--source" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--expected-frames") { try { const auto report = smartcut::media::validate_mkv_boundary(argv[3], argv[5], checked_u64(argv[7], "--expected-frames")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; } catch (const std::exception& error) { std::cerr << "boundary validation failed: " << error.what() << '\n'; return 5; } }
  if (argc == 12 && std::string_view(argv[1]) == "join-mkv" && std::string_view(argv[2]) == "--copied" && std::string_view(argv[4]) == "--replacement" && std::string_view(argv[6]) == "--output" && std::string_view(argv[8]) == "--copied-first-frame" && std::string_view(argv[10]) == "--replacement-first-frame") { const auto report = smartcut::media::join_mkv_video_segments(argv[3], argv[5], argv[7], checked_u64(argv[9], "--copied-first-frame"), checked_u64(argv[11], "--replacement-first-frame")); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  if (argc == 10 && std::string_view(argv[1]) == "validate-join" && std::string_view(argv[2]) == "--copied" && std::string_view(argv[4]) == "--replacement" && std::string_view(argv[6]) == "--output" && std::string_view(argv[8]) == "--expected-frames") { const auto report = smartcut::media::validate_mkv_join(argv[3], argv[5], argv[7], checked_u64(argv[9], "--expected-frames")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 8 && std::string_view(argv[1]) == "render-report" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--first-frame" && std::string_view(argv[6]) == "--end-frame") {
    try { const auto identity = smartcut::core::SourceIdentity::from_file(argv[3]); smartcut::core::Project project; project.add_source({identity.source_uuid, identity.canonical_path}); project.add_segment({identity.source_uuid, 0, checked_u64(argv[5], "--first-frame"), checked_u64(argv[7], "--end-frame")}); std::cout << smartcut::core::RenderReport::from_plan(smartcut::core::RenderPlan::from_project(project)).to_json() << '\n'; return 0; }
    catch (const std::exception& error) { std::cerr << "render report failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 8 && std::string_view(argv[1]) == "render-plan" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--first-frame" && std::string_view(argv[6]) == "--end-frame") {
    try { const auto identity = smartcut::core::SourceIdentity::from_file(argv[3]); smartcut::core::Project project; smartcut::core::ProjectSource source{identity.source_uuid, identity.canonical_path}; if (const auto audio = smartcut::media::primary_audio_track(argv[3])) { source.audio_stream = audio->stream_index; source.audio_time_base_num = audio->time_base_num; source.audio_time_base_den = audio->time_base_den; source.audio_sample_rate = audio->sample_rate; source.audio_channels = audio->channels; } project.add_source(source); project.add_segment({identity.source_uuid, 0, checked_u64(argv[5], "--first-frame"), checked_u64(argv[7], "--end-frame")}); std::cout << smartcut::core::RenderPlan::from_project(project).to_json() << '\n'; return 0; }
    catch (const std::exception& error) { std::cerr << "render plan failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 8 && std::string_view(argv[1]) == "explain-plan" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--first-frame" && std::string_view(argv[6]) == "--end-frame") {
    try { const auto identity = smartcut::core::SourceIdentity::from_file(argv[3]); smartcut::core::Project project; smartcut::core::ProjectSource source{identity.source_uuid, identity.canonical_path}; if (const auto audio = smartcut::media::primary_audio_track(argv[3])) { source.audio_stream = audio->stream_index; source.audio_time_base_num = audio->time_base_num; source.audio_time_base_den = audio->time_base_den; source.audio_sample_rate = audio->sample_rate; source.audio_channels = audio->channels; } project.add_source(source); project.add_segment({identity.source_uuid, 0, checked_u64(argv[5], "--first-frame"), checked_u64(argv[7], "--end-frame")}); std::cout << smartcut::core::RenderPlan::from_project(project).explain_text(); return 0; }
    catch (const std::exception& error) { std::cerr << "plan explanation failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 6 && std::string_view(argv[1]) == "validate-plan" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--plan") {
    try { const auto identity = smartcut::core::SourceIdentity::from_file(argv[3]); std::ifstream plan(argv[5], std::ios::binary); if (!plan) return 2; const std::string text((std::istreambuf_iterator<char>(plan)), {}); const std::string marker = "\"source_uuid\":\""; const auto start = text.find(marker); const auto end = start == std::string::npos ? std::string::npos : text.find('"', start + marker.size()); const auto uuid = start == std::string::npos || end == std::string::npos ? std::string{} : text.substr(start + marker.size(), end - start - marker.size()); if (uuid != identity.source_uuid) { std::cerr << "plan source identity mismatch\n"; return 5; } std::cout << "plan valid for " << identity.source_uuid << '\n'; return 0; }
    catch (const std::exception& error) { std::cerr << "plan validation failed: " << error.what() << '\n'; return 4; }
  }
  if (argc >= 4 && std::string_view(argv[1]) == "audio-timing" && std::string_view(argv[2]) == "--input") {
    std::size_t max_packets = 8; for (int i = 4; i + 1 < argc; ++i) if (std::string_view(argv[i]) == "--max-packets") max_packets = checked_size(argv[i + 1], "--max-packets");
    std::cout << smartcut::media::probe_audio_timing(argv[3], max_packets) << '\n'; return 0;
  }
  if (argc == 8 && std::string_view(argv[1]) == "audio-select" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--video-start-pts" && std::string_view(argv[6]) == "--video-end-pts") { const auto report = smartcut::media::select_audio_packets(argv[3], checked_i64(argv[5], "--video-start-pts"), checked_i64(argv[7], "--video-end-pts")); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  if (argc == 10 && std::string_view(argv[1]) == "copy-audio-window" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--video-start-pts" && std::string_view(argv[8]) == "--video-end-pts") { const auto report = smartcut::media::copy_mkv_audio_window(argv[3], argv[5], checked_i64(argv[7], "--video-start-pts"), checked_i64(argv[9], "--video-end-pts")); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  if (argc == 10 && std::string_view(argv[1]) == "validate-audio-copy" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--video-start-pts" && std::string_view(argv[8]) == "--video-end-pts") { const auto report = smartcut::media::validate_mkv_audio_copy(argv[3], argv[5], checked_i64(argv[7], "--video-start-pts"), checked_i64(argv[9], "--video-end-pts")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 8 && std::string_view(argv[1]) == "mux-mkv" && std::string_view(argv[2]) == "--video" && std::string_view(argv[4]) == "--audio" && std::string_view(argv[6]) == "--output") { const auto report = smartcut::media::mux_mkv_video_audio(argv[3], argv[5], argv[7]); std::cout << report << '\n'; return report.find("\"error\"") == std::string::npos ? 0 : 4; }
  if (argc == 8 && std::string_view(argv[1]) == "validate-mkv-av" && std::string_view(argv[2]) == "--video" && std::string_view(argv[4]) == "--audio" && std::string_view(argv[6]) == "--output") { const auto report = smartcut::media::validate_mkv_video_audio(argv[3], argv[5], argv[7]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 6 && std::string_view(argv[1]) == "export-mkv" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output") { const auto report = smartcut::media::export_mkv(argv[3], argv[5]); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 10 && std::string_view(argv[1]) == "export-range-mkv" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-frame" && std::string_view(argv[8]) == "--end-frame") { const auto report = smartcut::media::export_mkv_range(argv[3], argv[5], checked_size(argv[7], "--first-frame"), checked_size(argv[9], "--end-frame")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 10 && std::string_view(argv[1]) == "validate-range-mkv" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--output" && std::string_view(argv[6]) == "--first-frame" && std::string_view(argv[8]) == "--end-frame") { const auto report = smartcut::media::validate_mkv_timed_range(argv[3], argv[5], checked_size(argv[7], "--first-frame"), checked_size(argv[9], "--end-frame")); std::cout << report << '\n'; return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5; }
  if (argc == 6 && std::string_view(argv[1]) == "validate-render-report" && std::string_view(argv[2]) == "--report" && std::string_view(argv[4]) == "--validation") { std::ifstream report_file(argv[3], std::ios::binary); std::ifstream validation_file(argv[5], std::ios::binary); if (!report_file || !validation_file) return 2; const std::string report((std::istreambuf_iterator<char>(report_file)), {}); const std::string validation((std::istreambuf_iterator<char>(validation_file)), {}); const bool audio_ready = report.find("\"audio_ready\":true") != std::string::npos; const bool passed = validation.find("\"status\":\"PASSED\"") != std::string::npos; std::cout << "{\"schema\":\"render-completion-v1\",\"status\":\"" << (audio_ready && passed ? "PASSED" : "FAILED VALIDATION") << "\",\"audio_ready\":" << (audio_ready ? "true" : "false") << ",\"source_bound\":false,\"output_bound\":false,\"tracks_validated\":" << (passed ? "true" : "false") << "}\n"; return audio_ready && passed ? 0 : 5; }
  if (argc == 10 && std::string_view(argv[1]) == "validate-render-report" && std::string_view(argv[2]) == "--report" && std::string_view(argv[4]) == "--validation" && std::string_view(argv[6]) == "--audio-validation" && std::string_view(argv[8]) == "--output") { std::ifstream report_file(argv[3], std::ios::binary); std::ifstream validation_file(argv[5], std::ios::binary); std::ifstream audio_file(argv[7], std::ios::binary); if (!report_file || !validation_file || !audio_file) return 2; const std::string report((std::istreambuf_iterator<char>(report_file)), {}); const std::string validation((std::istreambuf_iterator<char>(validation_file)), {}); const std::string audio((std::istreambuf_iterator<char>(audio_file)), {}); const auto report_uuid_start = report.find("\"source_uuid\":\""); const auto report_uuid_end = report_uuid_start == std::string::npos ? std::string::npos : report.find('"', report_uuid_start + 15); const auto audio_uuid_start = audio.find("\"source_uuid\":\""); const auto audio_uuid_end = audio_uuid_start == std::string::npos ? std::string::npos : audio.find('"', audio_uuid_start + 15); const bool source_bound = report_uuid_start != std::string::npos && audio_uuid_start != std::string::npos && report.substr(report_uuid_start + 15, report_uuid_end - report_uuid_start - 15) == audio.substr(audio_uuid_start + 15, audio_uuid_end - audio_uuid_start - 15); const auto validation_output_start = validation.find("\"output_uuid\":\""); const auto validation_output_end = validation_output_start == std::string::npos ? std::string::npos : validation.find('"', validation_output_start + 15); const auto output_identity = smartcut::core::SourceIdentity::from_file(argv[9]); const bool output_bound = validation_output_start != std::string::npos && output_identity.source_uuid == validation.substr(validation_output_start + 15, validation_output_end - validation_output_start - 15); const bool audio_passed = audio.find("\"status\":\"PASSED\"") != std::string::npos; const bool tracks_passed = validation.find("\"status\":\"PASSED\"") != std::string::npos; const bool audio_ready = source_bound && output_bound && audio_passed; const bool passed = audio_ready && tracks_passed; std::cout << "{\"schema\":\"render-completion-v1\",\"status\":\"" << (passed ? "PASSED" : "FAILED VALIDATION") << "\",\"audio_ready\":" << (audio_ready ? "true" : "false") << ",\"source_bound\":" << (source_bound ? "true" : "false") << ",\"output_bound\":" << (output_bound ? "true" : "false") << ",\"tracks_validated\":" << (tracks_passed ? "true" : "false") << "}\n"; return passed ? 0 : 5; }
  if (argc == 8 && std::string_view(argv[1]) == "validate-render-report" && std::string_view(argv[2]) == "--report" && std::string_view(argv[4]) == "--validation" && std::string_view(argv[6]) == "--audio-validation") { std::ifstream report_file(argv[3], std::ios::binary); std::ifstream validation_file(argv[5], std::ios::binary); std::ifstream audio_file(argv[7], std::ios::binary); if (!report_file || !validation_file || !audio_file) return 2; const std::string report((std::istreambuf_iterator<char>(report_file)), {}); const std::string validation((std::istreambuf_iterator<char>(validation_file)), {}); const std::string audio((std::istreambuf_iterator<char>(audio_file)), {}); const auto report_uuid_start = report.find("\"source_uuid\":\""); const auto report_uuid_end = report_uuid_start == std::string::npos ? std::string::npos : report.find('"', report_uuid_start + 15); const auto audio_uuid_start = audio.find("\"source_uuid\":\""); const auto audio_uuid_end = audio_uuid_start == std::string::npos ? std::string::npos : audio.find('"', audio_uuid_start + 15); const bool source_bound = report_uuid_start != std::string::npos && audio_uuid_start != std::string::npos && report.substr(report_uuid_start + 15, report_uuid_end - report_uuid_start - 15) == audio.substr(audio_uuid_start + 15, audio_uuid_end - audio_uuid_start - 15); const bool has_audio_operation = report.find("\"audio_operations\":") != std::string::npos; const bool audio_passed = audio.find("\"status\":\"PASSED\"") != std::string::npos; const bool tracks_passed = validation.find("\"status\":\"PASSED\"") != std::string::npos; const bool audio_ready = source_bound && (report.find("\"audio_ready\":true") != std::string::npos || (has_audio_operation && audio_passed)); const bool passed = audio_ready && tracks_passed; std::cout << "{\"schema\":\"render-completion-v1\",\"status\":\"" << (passed ? "PASSED" : "FAILED VALIDATION") << "\",\"audio_ready\":" << (audio_ready ? "true" : "false") << ",\"source_bound\":" << (source_bound ? "true" : "false") << ",\"output_bound\":false,\"tracks_validated\":" << (tracks_passed ? "true" : "false") << "}\n"; return passed ? 0 : 5; }
  if (argc > 1 && std::string_view(argv[1]) == "sync") {
    if (argc != 16) { std::cerr << "usage: smartcut-cli sync --audio-pts A --video-pts V --tolerance T --audio-num N --audio-den D --video-num N --video-den D\n"; return 2; }
    std::int64_t audio_pts = 0, video_pts = 0, tolerance = 0, audio_num = 1, audio_den = 1, video_num = 1, video_den = 1;
    for (int i = 2; i + 1 < argc; i += 2) {
      const std::string_view option = argv[i]; const auto value = checked_i64(argv[i + 1], option);
      if (option == "--audio-pts") audio_pts = value; else if (option == "--video-pts") video_pts = value; else if (option == "--tolerance") tolerance = value;
      else if (option == "--audio-num") audio_num = value; else if (option == "--audio-den") audio_den = value; else if (option == "--video-num") video_num = value; else if (option == "--video-den") video_den = value; else { std::cerr << "unknown sync option\n"; return 2; }
    }
    smartcut::core::PreviewSynchronizer synchronizer({audio_num, audio_den}, {video_num, video_den}, tolerance);
    const auto action = synchronizer.update(audio_pts, video_pts);
    const char* action_name = action == smartcut::core::SyncAction::present ? "present" : action == smartcut::core::SyncAction::hold_video ? "hold_video" : "advance_video";
    std::cout << "{\"schema\":\"preview-sync-v1\",\"drift_ticks\":" << synchronizer.drift_ticks() << ",\"action\":\"" << action_name << "\"}\n";
    return 0;
  }
  if (argc > 1 && std::string_view(argv[1]) == "preview") {
    if (argc < 6 || std::string_view(argv[2]) != "--input" || std::string_view(argv[4]) != "--frame") { std::cerr << "usage: smartcut-cli preview --input <container> --frame <index> [--bgra]\n"; return 2; }
    const bool bgra = argc > 6 && (std::string_view(argv[6]) == "--bgra" || std::string_view(argv[6]) == "--tone-map-sdr");
    const bool tone_map = argc > 6 && std::string_view(argv[6]) == "--tone-map-sdr";
    const auto frame = smartcut::media::decode_preview_frame(argv[3], checked_size(argv[5], "--frame"));
    const auto converted_bgra = bgra ? smartcut::media::convert_preview_to_bgra(frame) : frame;
    const auto converted = tone_map ? smartcut::media::tone_map_bgra_sdr(converted_bgra) : converted_bgra;
    smartcut::core::PreviewFrameTransport transport(1);
    if (!converted || !transport.publish(converted)) { std::cerr << "preview decode/conversion/publish failed\n"; return 4; }
    const auto acquired = transport.acquire();
    if (!acquired || !transport.acknowledge(acquired->sequence)) { std::cerr << "preview acknowledgement failed\n"; return 4; }
    std::cout << "{\"schema\":\"preview-frame-v1\",\"sequence\":" << acquired->sequence << ",\"frame_index\":" << acquired->frame_index << ",\"width\":" << acquired->width << ",\"height\":" << acquired->height << ",\"stride\":" << acquired->stride << ",\"pixel_format\":" << acquired->pixel_format << ",\"pixels\":" << acquired->pixels.size() << ",\"display_color_mode\":\"" << acquired->display_color_mode << "\",\"tone_mapped\":" << (acquired->tone_mapped ? "true" : "false") << ",\"acknowledged\":true}\n";
    return 0;
  }
  if (argc > 1 && std::string_view(argv[1]) == "frame") {
    if (argc < 6 || std::string_view(argv[2]) != "--input" || std::string_view(argv[4]) != "--frame") { std::cerr << "usage: smartcut-cli frame --input <container> --frame <index> [--max-decode N]\n"; return 2; }
    std::size_t max_decode = 0;
    for (int i = 6; i + 1 < argc; ++i) if (std::string_view(argv[i]) == "--max-decode") max_decode = checked_size(argv[i + 1], "--max-decode");
    try { std::cout << smartcut::media::decode_frame(argv[3], checked_size(argv[5], "--frame"), max_decode) << '\n'; return 0; }
    catch (const std::exception& error) { std::cerr << "frame decode failed: " << error.what() << '\n'; return 4; }
  }
  if (argc > 1 && std::string_view(argv[1]) == "validate-index") {
    if (argc != 6 || std::string_view(argv[2]) != "--input" || std::string_view(argv[4]) != "--index") { std::cerr << "usage: smartcut-cli validate-index --input <source> --index <cache.json>\n"; return 2; }
    try {
      std::ifstream cache(argv[5], std::ios::binary);
      if (!cache) { std::cerr << "cannot open index: " << argv[5] << '\n'; return 2; }
      const std::string document((std::istreambuf_iterator<char>(cache)), {});
      const auto validation = smartcut::media::validate_hevc_index_cache(argv[3], document);
      std::cout << validation.to_json() << '\n';
      return validation.valid() ? 0 : 5;
    } catch (const std::exception& error) { std::cerr << "index validation failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 6 && std::string_view(argv[1]) == "repair-index" && std::string_view(argv[2]) == "--input" && std::string_view(argv[4]) == "--index") {
    try { const auto validation = smartcut::media::recover_hevc_index_cache(argv[3], argv[5]); std::cout << validation.to_json() << '\n'; return validation.valid() ? 0 : 5; }
    catch (const std::exception& error) { std::cerr << "index recovery failed: " << error.what() << '\n'; return 4; }
  }
  if (argc > 1 && std::string_view(argv[1]) == "index") {
    if (argc < 4 || std::string_view(argv[2]) != "--input") { std::cerr << "usage: smartcut-cli index --input <annex-b-hevc> [--output <index.json>]\n"; return 2; }
    std::string output_path;
    for (int i = 4; i + 1 < argc; ++i) if (std::string_view(argv[i]) == "--output") output_path = argv[i + 1];
    const auto report = smartcut::media::make_hevc_index_cache(argv[3]);
    if (report.empty()) { std::cerr << "index generation failed\n"; return 4; }
    if (output_path.empty()) std::cout << report << '\n';
    else { if (!smartcut::media::write_hevc_index_cache_atomic(argv[3], output_path)) { std::cerr << "cannot write index: " << output_path << '\n'; return 2; } std::cout << "indexed " << argv[3] << " -> " << output_path << '\n'; }
    return 0;
  }
  if (argc > 1 && std::string_view(argv[1]) == "probe") {
    if (argc != 4 || std::string_view(argv[2]) != "--input") {
      std::cerr << "usage: smartcut-cli probe --input <source-file>\n";
      return 2;
    }
    try { std::cout << smartcut::media::probe_container(argv[3]) << '\n'; return 0; }
    catch (const std::exception& error) { std::cerr << "probe failed: " << error.what() << '\n'; return 4; }
  }
  if (argc == 2 && std::string_view(argv[1]) == "codec-capabilities") {
    const auto report = smartcut::media::codec_capabilities_report();
    std::cout << report << '\n';
    return report.find("\"status\":\"PASSED\"") != std::string::npos ? 0 : 5;
  }
  if (argc > 1 && std::string_view(argv[1]) == "metadata-lab") return metadata_lab(argc, argv);
  if (argc > 1 && std::string_view(argv[1]) == "--versions") {
    std::cout << "smartcut-cli " << smartcut::build_info::application_version << "\n";
    std::cout << "ffmpeg " << smartcut::build_info::ffmpeg_version << " @ " << smartcut::build_info::ffmpeg_revision << "\n";
    std::cout << "x264 @ " << smartcut::build_info::x264_revision << "\n";
    std::cout << "x265 " << smartcut::build_info::x265_version << "\n";
    std::cout << "libaom " << smartcut::build_info::libaom_version << "\n";
    std::cout << "libvpx " << smartcut::build_info::libvpx_version << "\n";
    std::cout << "libdovi " << smartcut::build_info::libdovi_version << "\n";
    std::cout << "qt " << smartcut::build_info::qt_version << "\n";
    std::cout << "renderer " << smartcut::build_info::renderer << "\n";
    std::cout << "tests " << smartcut::build_info::test_framework << "\n";
    return 0;
  }
  std::cout << "SmartCut64 CLI bootstrap (M2)\n";
  return 0;
  } catch (const std::exception& error) {
    std::cerr << "smartcut-cli: invalid request: " << error.what() << '\n';
    return 2;
  } catch (...) {
    std::cerr << "smartcut-cli: invalid request\n";
    return 2;
  }
}




