///|
// DCL (Data Control Language) parsing functions

///|
fn Parser::parse_grant_statement(
  self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[GrantStmt] raise ParserError {
  let tokens = self.expect_token(tokens, Keyword(Grant))

  // Parse privileges
  let (privileges, tokens) = self.parse_privilege_list(tokens)

  // Parse ON
  let tokens = self.expect_token(tokens, Keyword(On))

  // Parse objects (tables, views, etc.)
  let (objects, tokens) = self.parse_object_name_list(tokens)

  // Parse TO
  let tokens = self.expect_token(tokens, Keyword(To))

  // Parse grantees (users/roles)
  let (grantees, tokens) = self.parse_grantee_list(tokens)

  // Parse optional WITH GRANT OPTION
  let (with_grant_option, tokens) = match tokens {
    [Keyword(With), Keyword(Grant), Keyword(Option), .. tokens] =>
      (true, tokens)
    _ => (false, tokens)
  }
  ({ privileges, objects, grantees, with_grant_option }, tokens)
}

///|
fn Parser::parse_revoke_statement(
  self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[RevokeStmt] raise ParserError {
  let tokens = self.expect_token(tokens, Keyword(Revoke))

  // Parse optional GRANT OPTION FOR
  let (grant_option_for, tokens) = match tokens {
    [Keyword(Grant), Keyword(Option), Keyword(For), .. tokens] => (true, tokens)
    _ => (false, tokens)
  }

  // Parse privileges
  let (privileges, tokens) = self.parse_privilege_list(tokens)

  // Parse ON
  let tokens = self.expect_token(tokens, Keyword(On))

  // Parse objects (tables, views, etc.)
  let (objects, tokens) = self.parse_object_name_list(tokens)

  // Parse FROM
  let tokens = self.expect_token(tokens, Keyword(From))

  // Parse grantees (users/roles)
  let (grantees, tokens) = self.parse_grantee_list(tokens)

  // Parse optional RESTRICT | CASCADE
  let (cascade, tokens) = match tokens {
    [Keyword(Restrict), .. tokens] => (Some(RevokeOption::Restrict), tokens)
    [Keyword(Cascade), .. tokens] => (Some(RevokeOption::Cascade), tokens)
    _ => (None, tokens)
  }
  ({ grant_option_for, privileges, objects, grantees, cascade }, tokens)
}

///|
fn Parser::parse_privilege_list(
  self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Array[Privilege]] raise ParserError {
  let privileges = []

  // Parse first privilege
  let (privilege, tokens) = self.parse_privilege(tokens)
  privileges.push(privilege)

  // Parse additional privileges separated by commas
  let tokens = loop tokens {
    [Comma, .. rest_tokens] => {
      let (privilege, tokens) = self.parse_privilege(rest_tokens)
      privileges.push(privilege)
      continue tokens
    }
    tokens => break tokens
  }
  (privileges, tokens)
}

///|
fn Parser::parse_privilege(
  self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Privilege] raise ParserError {
  match tokens {
    [Keyword(All), .. tokens] => {
      // Check for optional PRIVILEGES keyword
      let tokens = match tokens {
        [Keyword(Privileges), .. tokens] => tokens
        _ => tokens
      }
      (Privilege::All, tokens)
    }
    [Keyword(Select), .. tokens] => {
      let (columns, tokens) = self.parse_optional_column_list(tokens)
      (Privilege::Select(columns), tokens)
    }
    [Keyword(Insert), .. tokens] => {
      let (columns, tokens) = self.parse_optional_column_list(tokens)
      (Privilege::Insert(columns), tokens)
    }
    [Keyword(Update), .. tokens] => {
      let (columns, tokens) = self.parse_optional_column_list(tokens)
      (Privilege::Update(columns), tokens)
    }
    [Keyword(Delete), .. tokens] => (Privilege::Delete, tokens)
    [Keyword(References), .. tokens] => {
      let (columns, tokens) = self.parse_optional_column_list(tokens)
      (Privilege::References(columns), tokens)
    }
    [Keyword(Create), .. tokens] => (Privilege::Create, tokens)
    [Keyword(Drop), .. tokens] => (Privilege::Drop, tokens)
    [Keyword(Alter), .. tokens] => (Privilege::Alter, tokens)
    [Keyword(Index), .. tokens] => (Privilege::Index, tokens)
    [Keyword(Usage), .. tokens] => (Privilege::Usage, tokens)
    [Keyword(Execute), .. tokens] => (Privilege::Execute, tokens)
    [Keyword(Connect), .. tokens] => (Privilege::Connect, tokens)
    [Keyword(Temporary), .. tokens] => (Privilege::Temporary, tokens)
    [Keyword(Temp), .. tokens] => (Privilege::Temporary, tokens)
    [token, .. _tokens] =>
      raise UnexpectedTokenMessageError(token, "expected privilege name")
    [] => raise InternalBug("parse_privilege: unexpected end of tokens")
  }
}

///|
fn Parser::parse_optional_column_list(
  _self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Array[String]?] raise ParserError {
  match tokens {
    [LParen, .. tokens] => {
      let columns = []
      let tokens = loop tokens {
        [Identifier(col), Comma, .. tokens] => {
          columns.push(col)
          continue tokens
        }
        [Identifier(col), RParen, .. tokens] => {
          columns.push(col)
          break tokens
        }
        [token, .. _tokens] =>
          raise UnexpectedTokenMessageError(token, "expected column name")
        [] =>
          raise InternalBug(
            "parse_optional_column_list: unexpected end of tokens",
          )
      }
      (Some(columns), tokens)
    }
    _ => (None, tokens)
  }
}

///|
fn Parser::parse_object_name_list(
  self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Array[ObjectName]] raise ParserError {
  let objects = []

  // Parse first object name
  let (obj_name, tokens) = self.parse_object_name(tokens)
  objects.push(obj_name)

  // Parse additional object names separated by commas
  let tokens = loop tokens {
    [Comma, .. rest_tokens] => {
      let (obj_name, tokens) = self.parse_object_name(rest_tokens)
      objects.push(obj_name)
      continue tokens
    }
    tokens => break tokens
  }
  (objects, tokens)
}

///|
fn Parser::parse_grantee_list(
  _self : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Array[String]] raise ParserError {
  let grantees = []

  // Parse first grantee
  let (grantee, tokens) = match tokens {
    [Identifier(name), .. tokens] => (name, tokens)
    [StringLiteral(name), .. tokens] => (name, tokens)
    [token, .. _tokens] =>
      raise UnexpectedTokenMessageError(token, "expected user or role name")
    [] => raise InternalBug("parse_grantee_list: unexpected end of tokens")
  }
  grantees.push(grantee)

  // Parse additional grantees separated by commas
  let tokens = loop tokens {
    [Comma, .. rest_tokens] => {
      let (grantee, tokens) = match rest_tokens {
        [Identifier(name), .. tokens] => (name, tokens)
        [StringLiteral(name), .. tokens] => (name, tokens)
        [token, .. _tokens] =>
          raise UnexpectedTokenMessageError(token, "expected user or role name")
        [] =>
          raise InternalBug(
            "parse_grantee_list: unexpected end of tokens after comma",
          )
      }
      grantees.push(grantee)
      continue tokens
    }
    tokens => break tokens
  }
  (grantees, tokens)
}

///|
// DCL statement tests

test "GRANT SELECT statement" {
  let tokens = "GRANT SELECT ON users TO alice;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|GRANT SELECT ON users TO alice;
    ),
  )
}

///|
test "GRANT multiple privileges statement" {
  let tokens = "GRANT SELECT, INSERT, UPDATE ON users TO alice, bob;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|GRANT SELECT, INSERT, UPDATE ON users TO alice, bob;
    ),
  )
}

///|
test "GRANT with column specification" {
  let tokens = "GRANT SELECT (name, email), UPDATE (email) ON users TO alice;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|GRANT SELECT(name, email), UPDATE(email) ON users TO alice;
    ),
  )
}

///|
test "GRANT ALL PRIVILEGES statement" {
  let tokens = "GRANT ALL PRIVILEGES ON users TO alice WITH GRANT OPTION;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|GRANT ALL PRIVILEGES ON users TO alice WITH GRANT OPTION;
    ),
  )
}

///|
test "REVOKE SELECT statement" {
  let tokens = "REVOKE SELECT ON users FROM alice;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REVOKE SELECT ON users FROM alice;
    ),
  )
}

///|
test "REVOKE with CASCADE" {
  let tokens = "REVOKE ALL PRIVILEGES ON users FROM alice CASCADE;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REVOKE ALL PRIVILEGES ON users FROM alice CASCADE;
    ),
  )
}

///|
test "REVOKE GRANT OPTION FOR" {
  let tokens = "REVOKE GRANT OPTION FOR SELECT ON users FROM alice RESTRICT;"
  let stmt = parse_sql(tokens)[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REVOKE GRANT OPTION FOR SELECT ON users FROM alice RESTRICT;
    ),
  )
}