///|
/// Severity used by parser and auditor diagnostics.
pub(all) enum Severity {
  Info
  Warning
  Error
} derive(Debug, Eq)

///|
/// Resource class used by CSP request simulation.
pub(all) enum ResourceKind {
  Script
  Style
  Image
  Font
  Connect
  Frame
  Media
  Worker
  Object
  Manifest
  Child
  Base
  Form
  Navigate
  Prefetch
  Other
} derive(Debug, Eq)

///|
/// Coarse source expression classification.
pub(all) enum SourceKind {
  Keyword
  Scheme
  Host
  Nonce
  Hash
  Wildcard
  UnknownSource
} derive(Debug, Eq)

///|
/// One source expression inside a directive.
pub(all) struct Source {
  raw : String
  kind : SourceKind
  value : String
  line : Int
} derive(Debug, Eq)

///|
/// One CSP directive with its ordered sources.
pub(all) struct Directive {
  name : String
  sources : Array[Source]
  raw_value : String
  line : Int
} derive(Debug, Eq)

///|
/// Parsed Content-Security-Policy header.
pub(all) struct Policy {
  directives : Array[Directive]
  diagnostics : Array[Finding]
} derive(Debug, Eq)

///|
/// Finding returned by parser, auditor or migration planner.
pub(all) struct Finding {
  severity : Severity
  code : String
  directive : String
  message : String
  line : Int
} derive(Debug, Eq)

///|
/// Request model for local CSP simulation.
pub(all) struct ResourceRequest {
  kind : ResourceKind
  url : String
  origin : String
  nonce : String
  is_inline : Bool
} derive(Debug, Eq)

///|
/// Result of checking one resource against a policy.
pub(all) struct Decision {
  allowed : Bool
  directive : String
  matched_source : String
  reason : String
} derive(Debug, Eq)

///|
/// Summary produced by migration planning from observed resources.
pub(all) struct MigrationPlan {
  directives : Array[Directive]
  findings : Array[Finding]
  normalized : String
} derive(Debug, Eq)

///|
fn severity_to_string(severity : Severity) -> String {
  match severity {
    Info => "info"
    Warning => "warning"
    Error => "error"
  }
}

///|
pub fn source_kind_to_string(kind : SourceKind) -> String {
  match kind {
    Keyword => "keyword"
    Scheme => "scheme"
    Host => "host"
    Nonce => "nonce"
    Hash => "hash"
    Wildcard => "wildcard"
    UnknownSource => "unknown"
  }
}

///|
fn resource_kind_to_string(kind : ResourceKind) -> String {
  match kind {
    Script => "script"
    Style => "style"
    Image => "image"
    Font => "font"
    Connect => "connect"
    Frame => "frame"
    Media => "media"
    Worker => "worker"
    Object => "object"
    Manifest => "manifest"
    Child => "child"
    Base => "base"
    Form => "form"
    Navigate => "navigate"
    Prefetch => "prefetch"
    Other => "other"
  }
}

///|
fn make_finding(
  severity : Severity,
  code : String,
  directive : String,
  message : String,
  line : Int,
) -> Finding {
  { severity, code, directive, message, line }
}

///|
fn make_source(
  raw : String,
  kind : SourceKind,
  value : String,
  line : Int,
) -> Source {
  { raw, kind, value, line }
}

///|
fn make_directive(
  name : String,
  sources : Array[Source],
  raw_value : String,
  line : Int,
) -> Directive {
  { name, sources, raw_value, line }
}

///|
fn request(
  kind : ResourceKind,
  url : String,
  origin : String,
  nonce : String,
  is_inline : Bool,
) -> ResourceRequest {
  { kind, url, origin, nonce, is_inline }
}

///|
pub fn script_request(url : String, origin : String) -> ResourceRequest {
  request(Script, url, origin, "", false)
}

///|
pub fn inline_script(nonce : String, origin : String) -> ResourceRequest {
  request(Script, "", origin, nonce, true)
}

///|
pub fn style_request(url : String, origin : String) -> ResourceRequest {
  request(Style, url, origin, "", false)
}

///|
pub fn image_request(url : String, origin : String) -> ResourceRequest {
  request(Image, url, origin, "", false)
}

///|
pub fn connect_request(url : String, origin : String) -> ResourceRequest {
  request(Connect, url, origin, "", false)
}