///|
/// Normalized provider adapter metadata.
pub(all) struct ProviderAdapter {
  provider : HookProvider
  event_header : String
  delivery_header : String
  signature_header : String?
} derive(Eq, Debug)

///|
/// Construct adapter metadata.
pub fn ProviderAdapter::ProviderAdapter(
  provider : HookProvider,
  event_header : StringView,
  delivery_header : StringView,
  signature_header? : StringView,
) -> ProviderAdapter {
  {
    provider,
    event_header: event_header.to_owned(),
    delivery_header: delivery_header.to_owned(),
    signature_header: signature_header.map(v => v.to_owned()),
  }
}

///|
/// GitHub adapter metadata.
pub fn github_adapter() -> ProviderAdapter {
  ProviderAdapter(
    GitHub,
    "x-github-event",
    "x-github-delivery",
    signature_header="x-hub-signature-256",
  )
}

///|
/// GitLab adapter metadata.
pub fn gitlab_adapter() -> ProviderAdapter {
  ProviderAdapter(
    GitLab,
    "x-gitlab-event",
    "x-gitlab-delivery",
    signature_header="x-gitlab-token",
  )
}

///|
/// Gitee adapter metadata.
pub fn gitee_adapter() -> ProviderAdapter {
  ProviderAdapter(
    Gitee,
    "x-gitee-event",
    "x-gitee-delivery",
    signature_header="x-gitee-token",
  )
}

///|
/// Feishu adapter metadata.
pub fn feishu_adapter() -> ProviderAdapter {
  ProviderAdapter(
    Feishu,
    "x-lark-request-event",
    "x-lark-request-id",
    signature_header="x-lark-signature",
  )
}

///|
/// WeCom adapter metadata.
pub fn wecom_adapter() -> ProviderAdapter {
  ProviderAdapter(
    WeCom,
    "x-wecom-event",
    "x-wecom-msgid",
    signature_header="x-wecom-signature",
  )
}

///|
/// Stripe adapter metadata.
pub fn stripe_adapter() -> ProviderAdapter {
  ProviderAdapter(
    Stripe,
    "stripe-event-type",
    "stripe-request-id",
    signature_header="stripe-signature",
  )
}

///|
/// Convert provider headers and body into a normalized request.
pub fn ProviderAdapter::parse_request(
  self : ProviderAdapter,
  headers : Map[String, String],
  body : StringView,
) -> HookRequest {
  let event_type = header_value(headers, self.event_header).unwrap_or("unknown")
  let delivery_id = header_value(headers, self.delivery_header).unwrap_or(
    "unknown",
  )
  HookRequest(self.provider, event_type, delivery_id, body, headers~)
}

///|
/// Parse provider headers and a JSON body into a normalized, enriched event.
pub fn ProviderAdapter::parse_event(
  self : ProviderAdapter,
  headers : Map[String, String],
  body : StringView,
) -> HookEvent {
  enrich_provider_event(self.parse_request(headers, body))
}

///|
/// Verify the configured signature header is present when the adapter has one.
pub fn ProviderAdapter::verify_presence(
  self : ProviderAdapter,
  request : HookRequest,
) -> VerificationResult {
  match self.signature_header {
    Some(header_name) =>
      SignatureVerifier("presence", header_name, "provider secret").verify_presence(
        request,
      )
    None => VerificationResult(Unsupported, "adapter has no signature header")
  }
}