#include "core/gop_planner.hpp"
namespace smartcut::core {
namespace {
bool safe_random_access(const media::HevcAccessUnit& unit) {
  // A zero NAL type denotes a synthetic/unit-test index from before the field
  // was introduced. Real indexes only accept BLA/IDR (16-20); CRA is repaired.
  return unit.random_access && (unit.closed_random_access || unit.random_access_nal_type == 0U);
}

void add_video_operation(RenderPlan& plan, const KeptSegment& segment, std::uint64_t first,
                         std::uint64_t end, bool copy) {
  if (end <= first) return;
  plan.add_operation({copy ? "CopyVideoPackets" : "EncodeVideoBoundary", segment.source_uuid,
                      segment.video_stream, static_cast<std::size_t>(-1), first, end,
                      copy ? "complete independently decodable GOP span"
                           : "partial or CRA/open GOP span; conservative boundary repair required",
                      copy ? "pending-audio-range-selection" : "video-only-boundary; audio-not-copied",
                      "video", 0, 0});
}
}  // namespace

RenderPlan plan_hevc_segment(const KeptSegment& segment, const std::vector<media::HevcAccessUnit>& access_units) {
  RenderPlan plan;
  if (segment.end_display_frame_exclusive <= segment.first_display_frame || segment.first_display_frame >= access_units.size()) return plan;
  const auto end = std::min<std::uint64_t>(segment.end_display_frame_exclusive, access_units.size());
  auto cursor = segment.first_display_frame;
  if (!safe_random_access(access_units[cursor])) {
    auto next_safe = cursor + 1;
    while (next_safe < end && !safe_random_access(access_units[next_safe])) ++next_safe;
    add_video_operation(plan, segment, cursor, next_safe, false);
    cursor = next_safe;
  }
  if (cursor < end) {
    auto copy_end = end;
    const bool ends_at_source = end == access_units.size();
    const bool ends_at_safe_boundary = !ends_at_source && safe_random_access(access_units[end]);
    if (!ends_at_source && !ends_at_safe_boundary) {
      copy_end = end;
      while (copy_end > cursor && !safe_random_access(access_units[copy_end])) --copy_end;
    }
    add_video_operation(plan, segment, cursor, copy_end, true);
    add_video_operation(plan, segment, copy_end, end, false);
  }
  plan.add_operation({"CopyAudioPackets", segment.source_uuid, segment.video_stream, static_cast<std::size_t>(-1), segment.first_display_frame, end, "audio overlap and retiming require source track probe", "pending-audio-range-selection", "audio", 0, 0});
  return plan;
}
RenderPlan plan_project_segments(const Project& project, const std::unordered_map<std::string, std::vector<media::HevcAccessUnit>>& indexes) {
  RenderPlan plan; if (!project.valid()) return plan;
  for (const auto& source : project.sources()) plan.add_source_fingerprint(source.source_uuid);
  for (const auto& segment : project.segments()) {
    const auto found = indexes.find(segment.source_uuid); if (found == indexes.end()) continue;
    const ProjectSource* project_source = nullptr;
    for (const auto& source : project.sources()) if (source.source_uuid == segment.source_uuid) { project_source = &source; break; }
    const bool audio_ready = project_source != nullptr && project_source->audio_stream != static_cast<std::size_t>(-1) &&
                             project_source->audio_time_base_num > 0 && project_source->audio_time_base_den > 0;
    const auto segment_plan = plan_hevc_segment(segment, found->second);
    for (auto operation : segment_plan.operations()) {
      if (project_source != nullptr) {
        operation.audio_stream = project_source->audio_stream;
        operation.audio_time_base_num = project_source->audio_time_base_num;
        operation.audio_time_base_den = project_source->audio_time_base_den;
      }
      if (operation.kind == "CopyAudioPackets") {
        operation.audio_policy = audio_ready ? "copy-complete-source-audio-packets" : "pending-audio-range-selection";
        operation.reason = audio_ready ? "validated source audio track; packet window selected during timestamp planning"
                                       : "audio overlap and retiming require source track probe";
      } else if (audio_ready) {
        operation.audio_policy = "copy-complete-source-audio-packets";
      }
      plan.add_operation(std::move(operation));
    }
  }
  return plan;
}
}  // namespace smartcut::core
