'use strict';

/**
 * Reserved SQL keywords per dialect. Tables / columns named with one of
 * these words may collide with SQL parser tokens — sometimes fatally
 * (unquoted reference is a syntax error), sometimes silently (the
 * identifier gets reinterpreted as the keyword). Warning level only;
 * the project may choose to keep such names if it always quotes them.
 *
 * Sources (consulted at the time of writing — refresh when bumping a
 * dialect's supported version):
 *
 *   PostgreSQL  https://www.postgresql.org/docs/current/sql-keywords-appendix.html
 *               (entries marked "reserved" or "reserved (can be function or type)")
 *   MySQL 8.0   https://dev.mysql.com/doc/refman/8.0/en/keywords.html
 *               (entries marked R = reserved)
 *   Oracle 19c  https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Oracle-SQL-Reserved-Words-and-Keywords.html
 *   SQLite      https://www.sqlite.org/lang_keywords.html
 *
 * Lists below are intentionally not exhaustive — they focus on the
 * keywords developers are most likely to accidentally use as
 * identifiers (order, group, user, type, key, role, level, etc.).
 * False negatives are acceptable; the rule is a warning, not a gate.
 */

const POSTGRES = new Set([
  'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc',
  'asymmetric', 'authorization', 'binary', 'both', 'case', 'cast',
  'check', 'collate', 'collation', 'column', 'concurrently', 'constraint',
  'create', 'cross', 'current_catalog', 'current_date', 'current_role',
  'current_schema', 'current_time', 'current_timestamp', 'current_user',
  'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end',
  'except', 'false', 'fetch', 'for', 'foreign', 'freeze', 'from',
  'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially',
  'inner', 'intersect', 'into', 'is', 'isnull', 'join', 'lateral',
  'leading', 'left', 'like', 'limit', 'localtime', 'localtimestamp',
  'natural', 'not', 'notnull', 'null', 'offset', 'on', 'only', 'or',
  'order', 'outer', 'overlaps', 'placing', 'primary', 'references',
  'returning', 'right', 'select', 'session_user', 'similar', 'some',
  'symmetric', 'table', 'tablesample', 'then', 'to', 'trailing', 'true',
  'union', 'unique', 'user', 'using', 'variadic', 'verbose', 'when',
  'where', 'window', 'with'
]);

const MYSQL = new Set([
  'add', 'all', 'alter', 'analyze', 'and', 'as', 'asc', 'asensitive',
  'before', 'between', 'bigint', 'binary', 'blob', 'both', 'by',
  'call', 'cascade', 'case', 'change', 'char', 'character', 'check',
  'collate', 'column', 'condition', 'constraint', 'continue', 'convert',
  'create', 'cross', 'cube', 'cume_dist', 'current_date', 'current_time',
  'current_timestamp', 'current_user', 'cursor', 'database', 'databases',
  'day_hour', 'day_microsecond', 'day_minute', 'day_second', 'dec',
  'decimal', 'declare', 'default', 'delayed', 'delete', 'dense_rank',
  'desc', 'describe', 'deterministic', 'distinct', 'distinctrow', 'div',
  'double', 'drop', 'dual', 'each', 'else', 'elseif', 'enclosed',
  'escaped', 'except', 'exists', 'exit', 'explain', 'false', 'fetch',
  'first_value', 'float', 'for', 'force', 'foreign', 'from', 'fulltext',
  'function', 'generated', 'grant', 'group', 'grouping', 'groups',
  'having', 'high_priority', 'hour_microsecond', 'hour_minute',
  'hour_second', 'if', 'ignore', 'in', 'index', 'infile', 'inner',
  'inout', 'insensitive', 'insert', 'int', 'integer', 'interval', 'into',
  'is', 'iterate', 'join', 'json_table', 'key', 'keys', 'kill', 'lag',
  'last_value', 'lead', 'leading', 'leave', 'left', 'like', 'limit',
  'linear', 'lines', 'load', 'localtime', 'localtimestamp', 'lock',
  'long', 'longblob', 'longtext', 'loop', 'low_priority', 'master_bind',
  'match', 'mediumblob', 'mediumint', 'mediumtext', 'middleint',
  'minute_microsecond', 'minute_second', 'mod', 'modifies', 'natural',
  'not', 'no_write_to_binlog', 'nth_value', 'ntile', 'null', 'numeric',
  'of', 'on', 'optimize', 'optimizer_costs', 'option', 'optionally', 'or',
  'order', 'out', 'outer', 'outfile', 'over', 'partition', 'percent_rank',
  'precision', 'primary', 'procedure', 'purge', 'range', 'rank', 'read',
  'reads', 'read_write', 'real', 'recursive', 'references', 'regexp',
  'release', 'rename', 'repeat', 'replace', 'require', 'resignal',
  'restrict', 'return', 'revoke', 'right', 'rlike', 'row', 'rows',
  'row_number', 'schema', 'schemas', 'second_microsecond', 'select',
  'sensitive', 'separator', 'set', 'show', 'signal', 'smallint', 'spatial',
  'specific', 'sql', 'sqlexception', 'sqlstate', 'sqlwarning',
  'sql_big_result', 'sql_calc_found_rows', 'sql_small_result', 'ssl',
  'starting', 'stored', 'straight_join', 'system', 'table', 'terminated',
  'then', 'tinyblob', 'tinyint', 'tinytext', 'to', 'trailing', 'trigger',
  'true', 'undo', 'union', 'unique', 'unlock', 'unsigned', 'update',
  'usage', 'use', 'using', 'utc_date', 'utc_time', 'utc_timestamp',
  'values', 'varbinary', 'varchar', 'varcharacter', 'varying', 'virtual',
  'when', 'where', 'while', 'window', 'with', 'write', 'xor',
  'year_month', 'zerofill'
]);

const ORACLE = new Set([
  'access', 'add', 'all', 'alter', 'and', 'any', 'as', 'asc', 'audit',
  'between', 'by', 'char', 'check', 'cluster', 'column', 'comment',
  'compress', 'connect', 'create', 'current', 'date', 'decimal', 'default',
  'delete', 'desc', 'distinct', 'drop', 'else', 'exclusive', 'exists',
  'file', 'float', 'for', 'from', 'grant', 'group', 'having', 'identified',
  'immediate', 'in', 'increment', 'index', 'initial', 'insert', 'integer',
  'intersect', 'into', 'is', 'level', 'like', 'lock', 'long', 'maxextents',
  'minus', 'mlslabel', 'mode', 'modify', 'noaudit', 'nocompress', 'not',
  'nowait', 'null', 'number', 'of', 'offline', 'on', 'online', 'option',
  'or', 'order', 'pctfree', 'prior', 'public', 'raw', 'rename', 'resource',
  'revoke', 'row', 'rowid', 'rownum', 'rows', 'select', 'session', 'set',
  'share', 'size', 'smallint', 'start', 'successful', 'synonym', 'sysdate',
  'table', 'then', 'to', 'trigger', 'uid', 'union', 'unique', 'update',
  'user', 'validate', 'values', 'varchar', 'varchar2', 'view', 'whenever',
  'where', 'with'
]);

const SQLITE = new Set([
  'abort', 'action', 'add', 'after', 'all', 'alter', 'always', 'analyze',
  'and', 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin',
  'between', 'by', 'cascade', 'case', 'cast', 'check', 'collate',
  'column', 'commit', 'conflict', 'constraint', 'create', 'cross',
  'current', 'current_date', 'current_time', 'current_timestamp',
  'database', 'default', 'deferrable', 'deferred', 'delete', 'desc',
  'detach', 'distinct', 'do', 'drop', 'each', 'else', 'end', 'escape',
  'except', 'exclude', 'exclusive', 'exists', 'explain', 'fail', 'filter',
  'first', 'following', 'for', 'foreign', 'from', 'full', 'generated',
  'glob', 'group', 'groups', 'having', 'if', 'ignore', 'immediate', 'in',
  'index', 'indexed', 'initially', 'inner', 'insert', 'instead',
  'intersect', 'into', 'is', 'isnull', 'join', 'key', 'last', 'left',
  'like', 'limit', 'match', 'materialized', 'natural', 'no', 'not',
  'nothing', 'notnull', 'null', 'nulls', 'of', 'offset', 'on', 'or',
  'order', 'others', 'outer', 'over', 'partition', 'plan', 'pragma',
  'preceding', 'primary', 'query', 'raise', 'range', 'recursive',
  'references', 'regexp', 'reindex', 'release', 'rename', 'replace',
  'restrict', 'returning', 'right', 'rollback', 'row', 'rows', 'savepoint',
  'select', 'set', 'table', 'temp', 'temporary', 'then', 'ties', 'to',
  'transaction', 'trigger', 'unbounded', 'union', 'unique', 'update',
  'using', 'vacuum', 'values', 'view', 'virtual', 'when', 'where',
  'window', 'with', 'without'
]);

const DIALECT_KEYWORDS = {
  postgres: POSTGRES,
  mysql: MYSQL,
  oracle: ORACLE,
  sqlite: SQLITE
};

function getReservedKeywords(dialect) {
  return DIALECT_KEYWORDS[dialect] || new Set();
}

function isSupportedDialect(dialect) {
  return Object.prototype.hasOwnProperty.call(DIALECT_KEYWORDS, dialect);
}

module.exports = {
  POSTGRES,
  MYSQL,
  ORACLE,
  SQLITE,
  getReservedKeywords,
  isSupportedDialect
};
