///|
pub struct PayloadRule {
  key : String
  required : Bool
  expected_value : String
} derive(Eq, Debug)

///|
pub fn PayloadRule::new(
  key : String,
  required? : Bool = true,
  expected_value? : String = "",
) -> PayloadRule {
  { key, required, expected_value }
}

///|
pub struct PayloadSchema {
  name : String
  rules : Array[PayloadRule]
} derive(Eq, Debug)

///|
pub fn PayloadSchema::new(
  name : String,
  rules : Array[PayloadRule],
) -> PayloadSchema {
  { name, rules }
}

///|
pub struct PayloadValidationError {
  key : String
  message : String
} derive(Eq, Debug)

///|
pub fn PayloadValidationError::new(
  key : String,
  message : String,
) -> PayloadValidationError {
  { key, message }
}

///|
pub fn validate_payload_schema(
  schema : PayloadSchema,
  fields : Array[PayloadField],
) -> Array[PayloadValidationError] {
  let mut count = 0
  for i in 0.. if value != rule.expected_value { count = count + 1 }
        None => ()
      }
    }
  }
  let mut offset = 0
  Array::makei(count, _ => {
    while offset < schema.rules.length() {
      let rule = schema.rules[offset]
      offset = offset + 1
      let found = payload_value(fields, rule.key)
      if rule.required && found is None {
        return PayloadValidationError::new(rule.key, "required field missing")
      }
      if rule.expected_value != "" {
        match found {
          Some(value) =>
            if value != rule.expected_value {
              return PayloadValidationError::new(rule.key, "unexpected value")
            }
          None => ()
        }
      }
    }
    PayloadValidationError::new("", "")
  })
}

///|
pub fn schema_is_valid(schema : PayloadSchema, body : String) -> Bool {
  validate_payload_schema(schema, parse_payload_fields(body)).length() == 0
}

///|
pub fn github_issue_schema() -> PayloadSchema {
  PayloadSchema::new("github_issue", [PayloadRule::new("action")])
}

///|
pub fn feishu_message_schema() -> PayloadSchema {
  PayloadSchema::new("feishu_message", [PayloadRule::new("event")])
}

///|
pub fn schema_for_event(
  provider : String,
  event_type : String,
) -> PayloadSchema? {
  if provider == "github" && event_type == "issues" {
    Some(github_issue_schema())
  } else if provider == "feishu" && event_type == "im.message.receive_v1" {
    Some(feishu_message_schema())
  } else {
    None
  }
}

///|
pub fn validate_request_payload(
  request : WebhookRequest,
  profile : ProviderProfile,
) -> Array[PayloadValidationError] {
  match schema_for_event(profile.name, provider_event_type(request, profile)) {
    Some(schema) =>
      validate_payload_schema(schema, parse_payload_fields(request.body))
    None => []
  }
}

///|
pub fn payload_error_text(errors : Array[PayloadValidationError]) -> String {
  let builder = StringBuilder::new()
  for i in 0..