// =============================================================================
// [DNA] M-A-A FRAMEWORK - Motivation-Attention-Action for Photon Empress Moore
//
// The Amygdala-inspired agency system that drives autonomous behavior.
//
// M = Motivation: Goal stack with priorities and deadlines
// A = Attention: Salience gating, context switching, focus management
// A = Action: Tool selection, execution, and outcome evaluation
//
// By Tadden Moore
// =============================================================================

#pragma once

#include <atomic>
#include <chrono>
#include <functional>
#include <mutex>
#include <optional>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>


namespace photon {
namespace maa {

// =============================================================================
// GOAL - A single motivation with priority and deadline
// =============================================================================
struct Goal {
  std::string id;          // Unique identifier
  std::string description; // Human-readable description
  int priority;            // 1-10 (1 = highest, 10 = lowest)
  std::chrono::time_point<std::chrono::system_clock> created;
  std::optional<std::chrono::time_point<std::chrono::system_clock>> deadline;

  // Goal state
  enum class State { PENDING, ACTIVE, BLOCKED, COMPLETED, FAILED };
  State state = State::PENDING;

  // Linked L1 anchor (from NGM)
  std::string l1_anchor; // e.g., "1.1!Tadden", "1.2!Family", "1.4!PhoSelf"

  // Required tools (if known)
  std::vector<std::string> required_tools;

  // Progress tracking
  float progress = 0.0f; // 0.0 - 1.0
  std::string last_action;

  // Comparison for priority queue (lower priority number = higher priority)
  bool operator<(const Goal &other) const {
    if (priority != other.priority)
      return priority > other.priority;
    // Earlier deadline = higher priority
    if (deadline && other.deadline)
      return *deadline > *other.deadline;
    if (deadline)
      return false; // Has deadline = higher priority
    if (other.deadline)
      return true;
    return created > other.created; // Earlier created = higher priority
  }
};

// =============================================================================
// MOTIVATION STACK - Priority queue of goals
// =============================================================================
class MotivationStack {
public:
  MotivationStack() = default;

  // Add a new goal
  std::string
  push(const std::string &description, int priority = 5,
       const std::string &l1_anchor = "1.4!PhoSelf",
       std::optional<std::chrono::seconds> deadline_from_now = std::nullopt) {
    std::lock_guard<std::mutex> lock(mx_);

    Goal g;
    g.id = generate_id();
    g.description = description;
    g.priority = priority;
    g.created = std::chrono::system_clock::now();
    g.l1_anchor = l1_anchor;
    if (deadline_from_now) {
      g.deadline = g.created + *deadline_from_now;
    }

    goals_.push(g);
    goal_map_[g.id] = g;

    return g.id;
  }

  // Get the highest priority goal (doesn't remove it)
  std::optional<Goal> peek() const {
    std::lock_guard<std::mutex> lock(mx_);
    if (goals_.empty())
      return std::nullopt;
    return goals_.top();
  }

  // Pop the highest priority goal
  std::optional<Goal> pop() {
    std::lock_guard<std::mutex> lock(mx_);
    if (goals_.empty())
      return std::nullopt;
    Goal g = goals_.top();
    goals_.pop();
    goal_map_.erase(g.id);
    return g;
  }

  // Update goal state
  void update_state(const std::string &id, Goal::State state) {
    std::lock_guard<std::mutex> lock(mx_);
    if (goal_map_.count(id)) {
      goal_map_[id].state = state;
    }
  }

  // Update goal progress
  void update_progress(const std::string &id, float progress,
                       const std::string &action = "") {
    std::lock_guard<std::mutex> lock(mx_);
    if (goal_map_.count(id)) {
      goal_map_[id].progress = progress;
      if (!action.empty())
        goal_map_[id].last_action = action;
    }
  }

  // Get all active goals (for status display)
  std::vector<Goal> get_all() const {
    std::lock_guard<std::mutex> lock(mx_);
    std::vector<Goal> result;
    for (const auto &[id, goal] : goal_map_) {
      result.push_back(goal);
    }
    return result;
  }

  size_t size() const {
    std::lock_guard<std::mutex> lock(mx_);
    return goals_.size();
  }

  bool empty() const {
    std::lock_guard<std::mutex> lock(mx_);
    return goals_.empty();
  }

private:
  mutable std::mutex mx_;
  std::priority_queue<Goal> goals_;
  std::unordered_map<std::string, Goal> goal_map_;
  int id_counter_ = 0;

  std::string generate_id() {
    return "goal_" + std::to_string(++id_counter_) + "_" +
           std::to_string(
               std::chrono::system_clock::now().time_since_epoch().count() %
               10000);
  }
};

// =============================================================================
// ATTENTION CONTEXT - What the system is currently focused on
// =============================================================================
struct AttentionContext {
  std::string current_goal_id;
  std::string current_tool;
  std::chrono::time_point<std::chrono::system_clock> focus_start;
  float salience_score = 0.0f; // 0.0 - 1.0 (how important is current focus?)

  // Context switching flags
  bool allow_interrupts = true;
  int interrupt_threshold = 3; // Only interrupt if new priority <= this

  // Recent context for short-term memory
  std::vector<std::string> recent_tokens; // Last N tokens processed
  std::vector<std::string> recent_tools;  // Last N tools used
};

// =============================================================================
// ATTENTION GATE - Salience scoring and context switching
// =============================================================================
class AttentionGate {
public:
  AttentionGate() = default;

  // Set current focus
  void focus_on(const std::string &goal_id, const std::string &tool = "") {
    std::lock_guard<std::mutex> lock(mx_);
    ctx_.current_goal_id = goal_id;
    ctx_.current_tool = tool;
    ctx_.focus_start = std::chrono::system_clock::now();
  }

  // Calculate salience score for a potential interrupt
  float calculate_salience(const Goal &incoming) const {
    float base =
        1.0f / (incoming.priority + 0.1f); // Lower priority = higher salience

    // Boost for deadlines
    if (incoming.deadline) {
      auto now = std::chrono::system_clock::now();
      auto time_left = std::chrono::duration_cast<std::chrono::minutes>(
          *incoming.deadline - now);
      if (time_left.count() < 60)
        base *= 2.0f; // Less than 1 hour = urgent
      if (time_left.count() < 5)
        base *= 3.0f; // Less than 5 min = critical
    }

    // Boost for L1 anchors (user/Family = highest)
    if (incoming.l1_anchor == "1.1!Tadden")
      base *= 1.5f;
    else if (incoming.l1_anchor == "1.2!Family")
      base *= 1.4f;
    else if (incoming.l1_anchor == "1.3!Pets+Safety")
      base *= 1.3f;

    return std::min(1.0f, base);
  }

  // Check if we should switch to a new goal
  bool should_switch(const Goal &incoming) const {
    std::lock_guard<std::mutex> lock(mx_);
    if (!ctx_.allow_interrupts)
      return false;
    if (incoming.priority <= ctx_.interrupt_threshold) {
      float salience = calculate_salience(incoming);
      return salience > ctx_.salience_score;
    }
    return false;
  }

  // Add token to recent context
  void add_token(const std::string &token) {
    std::lock_guard<std::mutex> lock(mx_);
    ctx_.recent_tokens.push_back(token);
    if (ctx_.recent_tokens.size() > 50) {
      ctx_.recent_tokens.erase(ctx_.recent_tokens.begin());
    }
  }

  // Add tool to recent context
  void add_tool(const std::string &tool) {
    std::lock_guard<std::mutex> lock(mx_);
    ctx_.recent_tools.push_back(tool);
    if (ctx_.recent_tools.size() > 10) {
      ctx_.recent_tools.erase(ctx_.recent_tools.begin());
    }
  }

  // Get current context
  AttentionContext get_context() const {
    std::lock_guard<std::mutex> lock(mx_);
    return ctx_;
  }

  // Set interrupt mode
  void set_interrupt_mode(bool allow, int threshold = 3) {
    std::lock_guard<std::mutex> lock(mx_);
    ctx_.allow_interrupts = allow;
    ctx_.interrupt_threshold = threshold;
  }

private:
  mutable std::mutex mx_;
  AttentionContext ctx_;
};

// =============================================================================
// ACTION RESULT - Outcome of a tool execution
// =============================================================================
struct ActionResult {
  bool success = false;
  std::string output;
  std::string error;
  std::chrono::milliseconds duration{0};
  float confidence = 0.0f; // How confident are we in the result?
};

// =============================================================================
// ACTION DISPATCHER - Tool selection and execution
// =============================================================================
class ActionDispatcher {
public:
  using ToolHandler = std::function<ActionResult(const std::string &args)>;

  ActionDispatcher() = default;

  // Register a tool
  void register_tool(const std::string &name, ToolHandler handler, int cost = 1,
                     bool requires_confirm = false) {
    std::lock_guard<std::mutex> lock(mx_);
    tools_[name] = {handler, cost, requires_confirm, 0, 0.0f};
  }

  // Execute a tool
  ActionResult execute(const std::string &tool_name, const std::string &args) {
    std::lock_guard<std::mutex> lock(mx_);

    auto it = tools_.find(tool_name);
    if (it == tools_.end()) {
      return {false, "", "Tool not found: " + tool_name,
              std::chrono::milliseconds(0), 0.0f};
    }

    auto &tool = it->second;
    auto start = std::chrono::steady_clock::now();

    // Execute
    ActionResult result = tool.handler(args);

    auto end = std::chrono::steady_clock::now();
    result.duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    // Update stats
    tool.use_count++;
    if (result.success) {
      tool.success_rate =
          (tool.success_rate * (tool.use_count - 1) + 1.0f) / tool.use_count;
    } else {
      tool.success_rate =
          (tool.success_rate * (tool.use_count - 1)) / tool.use_count;
    }

    return result;
  }

  // Get best tool for a goal (based on description matching and success rate)
  std::string suggest_tool(const Goal &goal) const {
    std::lock_guard<std::mutex> lock(mx_);

    // Simple keyword matching for now
    std::string desc_lower = goal.description;
    for (char &c : desc_lower)
      c = std::tolower(c);

    if (desc_lower.find("run") != std::string::npos ||
        desc_lower.find("code") != std::string::npos ||
        desc_lower.find("script") != std::string::npos) {
      return "2.1!Run Code";
    }
    if (desc_lower.find("device") != std::string::npos ||
        desc_lower.find("screen") != std::string::npos ||
        desc_lower.find("tap") != std::string::npos) {
      return "2.2!Device Control";
    }
    if (desc_lower.find("learn") != std::string::npos ||
        desc_lower.find("ai") != std::string::npos ||
        desc_lower.find("ask") != std::string::npos) {
      return "2.3!Learn from AI";
    }
    if (desc_lower.find("clone") != std::string::npos ||
        desc_lower.find("parallel") != std::string::npos ||
        desc_lower.find("bunshin") != std::string::npos) {
      return "2.4!KageBunshin(Clone)";
    }
    if (desc_lower.find("search") != std::string::npos ||
        desc_lower.find("memory") != std::string::npos ||
        desc_lower.find("find") != std::string::npos) {
      return "DeepSearch Memories";
    }

    // Default: no suggestion
    return "";
  }

  // Get tool stats
  struct ToolStats {
    std::string name;
    int use_count;
    float success_rate;
    int cost;
  };
  std::vector<ToolStats> get_stats() const {
    std::lock_guard<std::mutex> lock(mx_);
    std::vector<ToolStats> result;
    for (const auto &[name, tool] : tools_) {
      result.push_back({name, tool.use_count, tool.success_rate, tool.cost});
    }
    return result;
  }

private:
  struct ToolInfo {
    ToolHandler handler;
    int cost;
    bool requires_confirm;
    int use_count;
    float success_rate;
  };

  mutable std::mutex mx_;
  std::unordered_map<std::string, ToolInfo> tools_;
};

// =============================================================================
// MAA CONTROLLER - Coordinates Motivation, Attention, and Action
// =============================================================================
class MAAController {
public:
  MAAController() = default;

  MotivationStack &motivation() { return motivation_; }
  AttentionGate &attention() { return attention_; }
  ActionDispatcher &action() { return action_; }

  // Main tick function - call this in the agentic loop
  void tick() {
    tick_count_++;

    // Check for new goals and attention switching
    auto top_goal = motivation_.peek();
    if (top_goal) {
      auto ctx = attention_.get_context();

      // If no current focus, or should switch
      if (ctx.current_goal_id.empty() || attention_.should_switch(*top_goal)) {
        attention_.focus_on(top_goal->id);
        current_goal_ = *top_goal;

        // Suggest a tool
        std::string suggested = action_.suggest_tool(*top_goal);
        if (!suggested.empty()) {
          attention_.add_tool(suggested);
        }
      }
    }
  }

  // Get status report
  std::string status_report() const {
    std::string report = "=== M-A-A STATUS ===\n";
    report += "Tick: " + std::to_string(tick_count_) + "\n";
    report += "Goals: " + std::to_string(motivation_.size()) + "\n";

    auto ctx = attention_.get_context();
    report += "Focus: " +
              (ctx.current_goal_id.empty() ? "(none)" : ctx.current_goal_id) +
              "\n";
    report +=
        "Tool: " + (ctx.current_tool.empty() ? "(none)" : ctx.current_tool) +
        "\n";

    return report;
  }

  uint64_t tick_count() const { return tick_count_; }

private:
  MotivationStack motivation_;
  AttentionGate attention_;
  ActionDispatcher action_;

  Goal current_goal_;
  std::atomic<uint64_t> tick_count_{0};
};

} // namespace maa
} // namespace photon
