// Policy: JSON-based policy loader for PromptGate.
//
// A policy is a JSON document that describes which tool calls are allowed,
// denied, or require user confirmation. This module parses the JSON,
// validates it, and builds a ready-to-use Gate.

///|
/// One rule entry from the JSON policy file.
#derive(FromJson)
priv struct PolicyRule {
  rule_type : String
  tool : String
  action : String
  resource : String
}

///|
/// Top-level policy structure matching the JSON schema.
#derive(FromJson)
priv struct PolicyFile {
  version : String?
  rules : Array[PolicyRule]
}

///|
/// Error type for policy loading failures.
pub(all) suberror PolicyError {
  InvalidJson(String)
  MissingField(String)
  UnknownVersion(String)
  EmptyRules
}

///|
/// Load a Gate from a JSON policy string.
pub fn load_policy(json_str : String) -> Gate raise PolicyError {
  let file : PolicyFile = try {
    let parsed = @json.parse(json_str)
    @json.from_json(parsed)
  } catch {
    _ => raise PolicyError::InvalidJson("invalid JSON structure or fields")
  }

  match file.version {
    None => raise PolicyError::MissingField("version")
    Some(v) =>
      if v != "1" && v != "1.0" {
        raise PolicyError::UnknownVersion(v)
      }
  }

  if file.rules.length() == 0 {
    raise PolicyError::EmptyRules
  }

  let mut capabilities = CapabilitySet::new()
  let mut ask_rules : Array[Capability] = []

  for i = 0; i < file.rules.length(); i = i + 1 {
    let r = file.rules[i]
    let ri = i.to_string()
    if r.rule_type == "" {
      raise PolicyError::MissingField("rules[" + ri + "].rule_type")
    }
    if r.tool == "" {
      raise PolicyError::MissingField("rules[" + ri + "].tool")
    }
    let cap = new(r.tool, r.action, r.resource)
    match r.rule_type {
      "allow" => capabilities = capabilities.add_allow(cap)
      "deny" => capabilities = capabilities.add_deny(cap)
      "ask" => ask_rules = ask_rules + [cap]
      _ => raise PolicyError::InvalidJson("unknown rule type: " + r.rule_type)
    }
  }

  Gate::new(capabilities, ask_rules)
}