// =============================================================================
// [PLUG] ROUTER PROTOCOL - Bracket Command System for Photon Empress Moore
//
// The bracket protocol is the lingua franca between all Photon components:
//   [G: ...] = GUI to Core/Router
//   [P: ...] = Core to GUI/Router (Pho's output)
//   [E: ...] = Engine messages
//   [C: ...] = Control/System commands
//   [M: ...] = Memory operations
//   [T: ...] = Tool invocations
//   [K: ...] = Kage Bunshin (clone) messages
//
// By Tadden Moore
// =============================================================================

#pragma once

#include <functional>
#include <mutex>
#include <optional>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>


namespace photon {
namespace router {

// =============================================================================
// FRAME - Single bracket protocol message
// =============================================================================
struct Frame {
  char tag = '?';          // G, P, E, C, M, T, K
  std::string payload;     // Content after the colon
  std::string source;      // Where it came from
  std::string destination; // Where it's going (optional)
  uint64_t timestamp = 0;  // When it was created
  int priority = 5;        // 1 = highest, 10 = lowest

  // Quick constructors
  static Frame gui(const std::string &payload) {
    Frame f;
    f.tag = 'G';
    f.payload = payload;
    return f;
  }
  static Frame pho(const std::string &payload) {
    Frame f;
    f.tag = 'P';
    f.payload = payload;
    return f;
  }
  static Frame engine(const std::string &payload) {
    Frame f;
    f.tag = 'E';
    f.payload = payload;
    return f;
  }
  static Frame control(const std::string &payload) {
    Frame f;
    f.tag = 'C';
    f.payload = payload;
    return f;
  }
  static Frame memory(const std::string &payload) {
    Frame f;
    f.tag = 'M';
    f.payload = payload;
    return f;
  }
  static Frame tool(const std::string &payload) {
    Frame f;
    f.tag = 'T';
    f.payload = payload;
    return f;
  }
  static Frame kage(const std::string &payload) {
    Frame f;
    f.tag = 'K';
    f.payload = payload;
    return f;
  }

  // Serialize to wire format
  std::string serialize() const {
    return "[" + std::string(1, tag) + ": " + payload + "]\n";
  }
};

// =============================================================================
// FRAME PARSER - Parse bracket protocol messages
// =============================================================================
class FrameParser {
public:
  // Parse a single line into a Frame
  static std::optional<Frame> parse(const std::string &line) {
    std::string s = trim(line);
    if (s.size() < 4 || s[0] != '[')
      return std::nullopt;

    size_t colon = s.find(':');
    size_t rb = s.rfind(']');
    if (colon == std::string::npos || rb == std::string::npos)
      return std::nullopt;
    if (colon != 2)
      return std::nullopt; // "[X:"

    Frame f;
    f.tag = s[1];
    f.payload = trim(s.substr(colon + 1, rb - colon - 1));
    return f;
  }

private:
  static std::string trim(const std::string &s) {
    size_t a = 0, b = s.size();
    while (a < b &&
           (s[a] == ' ' || s[a] == '\t' || s[a] == '\r' || s[a] == '\n'))
      ++a;
    while (b > a && (s[b - 1] == ' ' || s[b - 1] == '\t' || s[b - 1] == '\r' ||
                     s[b - 1] == '\n'))
      -b;
    return s.substr(a, b - a);
  }
};

// =============================================================================
// COMMAND DEFINITIONS - Standard commands
// =============================================================================
namespace commands {

// GUI Commands (G:)
constexpr const char *GUI_USER_INPUT = "USR"; // User typed something
constexpr const char *GUI_COMMAND = "CMD";    // Command prefix (e.g., !run)
constexpr const char *GUI_STATUS = "STAT";    // Status request
constexpr const char *GUI_SETTINGS = "SET";   // Settings change

// Pho Commands (P:)
constexpr const char *PHO_RESPONSE = "RSP"; // Response to user
constexpr const char *PHO_STATUS = "STAT";  // Status update
constexpr const char *PHO_ERROR = "ERR";    // Error message
constexpr const char *PHO_COMPLETE = "END"; // Finished response
constexpr const char *PHO_THOUGHT = "THT";  // Internal thought (for debug)
constexpr const char *PHO_EMOTION = "EMO";  // Emotional state

// Engine Commands (E:)
constexpr const char *ENG_EMBED = "EMBED";   // Request embedding
constexpr const char *ENG_GENERATE = "GEN";  // Generate tokens
constexpr const char *ENG_TOKEN = "TOK";     // Single token output
constexpr const char *ENG_EMBEDDING = "EMB"; // Embedding result
constexpr const char *ENG_STATUS = "STAT";   // Engine status
constexpr const char *ENG_ERROR = "ERR";     // Engine error

// Control Commands (C:)
constexpr const char *CTL_START = "START";       // Start component
constexpr const char *CTL_STOP = "STOP";         // Stop component
constexpr const char *CTL_RESTART = "RESTART";   // Restart component
constexpr const char *CTL_HEALTH = "HEALTH";     // Health check
constexpr const char *CTL_SHUTDOWN = "SHUTDOWN"; // Graceful shutdown
constexpr const char *CTL_BOOST = "BOOST";       // Performance boost
constexpr const char *CTL_SLEEP = "SLEEP";       // Enter low-power mode

// Memory Commands (M:)
constexpr const char *MEM_STORE = "STORE";             // Store memory
constexpr const char *MEM_RECALL = "RECALL";           // Recall memory
constexpr const char *MEM_SEARCH = "SEARCH";           // Semantic search
constexpr const char *MEM_FLUSH = "FLUSH";             // Flush to disk
constexpr const char *MEM_CONSOLIDATE = "CONSOLIDATE"; // Spinal wash

// Tool Commands (T:)
constexpr const char *TOOL_RUN = "RUN";     // Run code
constexpr const char *TOOL_DEVICE = "DEV";  // Device control
constexpr const char *TOOL_LEARN = "LEARN"; // Learn from AI
constexpr const char *TOOL_DEEP = "DEEP";   // Deep search
constexpr const char *TOOL_COPY = "COPY";   // Copy/clone

// Kage Commands (K:)
constexpr const char *KAGE_SPAWN = "SPAWN";     // Spawn new clone
constexpr const char *KAGE_STATUS = "STATUS";   // Clone status
constexpr const char *KAGE_RESULT = "RESULT";   // Clone result
constexpr const char *KAGE_MERGE = "MERGE";     // Merge clone knowledge
constexpr const char *KAGE_DISMISS = "DISMISS"; // Dismiss clone

} // namespace commands

// =============================================================================
// MESSAGE ROUTER - Routes frames between components
// =============================================================================
class MessageRouter {
public:
  using Handler = std::function<void(const Frame &)>;

  MessageRouter() = default;

  // Register a handler for a tag
  void on(char tag, Handler handler) {
    std::lock_guard<std::mutex> lock(mx_);
    handlers_[tag].push_back(handler);
  }

  // Send a frame (routes to appropriate handlers)
  void route(const Frame &frame) {
    std::lock_guard<std::mutex> lock(mx_);

    // Log the frame
    log_.push_back(frame);
    if (log_.size() > 1000)
      log_.pop_front();

    // Find handlers
    auto it = handlers_.find(frame.tag);
    if (it != handlers_.end()) {
      for (auto &handler : it->second) {
        handler(frame);
      }
    }

    // Also call wildcard handlers
    auto wild = handlers_.find('*');
    if (wild != handlers_.end()) {
      for (auto &handler : wild->second) {
        handler(frame);
      }
    }
  }

  // Convenience: route from raw string
  void route(const std::string &line) {
    auto frame = FrameParser::parse(line);
    if (frame)
      route(*frame);
  }

  // Get recent logs
  std::vector<Frame> get_logs(size_t count = 100) const {
    std::lock_guard<std::mutex> lock(mx_);
    std::vector<Frame> result;
    size_t start = log_.size() > count ? log_.size() - count : 0;
    for (size_t i = start; i < log_.size(); ++i) {
      result.push_back(log_[i]);
    }
    return result;
  }

  // Clear handlers
  void clear() {
    std::lock_guard<std::mutex> lock(mx_);
    handlers_.clear();
  }

private:
  mutable std::mutex mx_;
  std::unordered_map<char, std::vector<Handler>> handlers_;
  std::deque<Frame> log_;
};

// =============================================================================
// QUICK HELPERS
// =============================================================================

// Parse a command payload (e.g., "RUN echo hello" -> ["RUN", "echo hello"])
inline std::pair<std::string, std::string>
parse_command(const std::string &payload) {
  size_t space = payload.find(' ');
  if (space == std::string::npos) {
    return {payload, ""};
  }
  return {payload.substr(0, space), payload.substr(space + 1)};
}

// Make a frame string
inline std::string make_frame(char tag, const std::string &payload) {
  return "[" + std::string(1, tag) + ": " + payload + "]\n";
}

} // namespace router
} // namespace photon
