const {
  sep1,
  sep,
  parens,
  semi,
  semi_opt,
  semis,
} = require('./util.js')

module.exports = {

  // ------------------------------------------------------------------------
  // module names
  // ------------------------------------------------------------------------

  _modid: $ => alias($.name, $.module_id),

  _modid_prefix: $ => prec('qualifying-module', seq($._modid, $._any_tight_dot)),

  _qualifying_module: $ => repeat1($._modid_prefix),

  module: $ => seq(repeat($._modid_prefix), $._modid),

  // ------------------------------------------------------------------------
  // import/export
  // ------------------------------------------------------------------------

  namespace: _ => choice('pattern', 'type'),

  _child_type: $ => seq(field('namespace', 'type'), field('type', $._tyconids)),

  _child: $ => choice(
    alias($._child_type, $.associated_type),
    $._qname,
  ),

  children: $ => parens($, sep(',', field('element', choice(alias('..', $.all_names), $._child)))),

  _ie_entity: $ => seq(
    optional(field('namespace', $.namespace)),
    choice(
      field('variable', $._varids),
      field('type', $._tyconids),
      field('operator', choice($._sym_prefix, $._pqsym)),
    ),
    optional(field('children', $.children)),
  ),

  // ------------------------------------------------------------------------
  // import
  // ------------------------------------------------------------------------

  import_list: $ => parens(
    $,
    sep(',', field('name', alias($._ie_entity, $.import_name))),
    optional(','),
  ),

  import: $ => seq(
    'import',
    optional('qualified'),
    optional(field('package', alias($.string, $.import_package))),
    field('module', $.module),
    optional('qualified'),
    optional(seq('as', field('alias', $.module))),
    optional(seq(
      optional('hiding'),
      field('names', $.import_list),
    )),
  ),

  // ------------------------------------------------------------------------
  // export
  // ------------------------------------------------------------------------

  module_export: $ => seq('module', field('module', $.module)),

  exports: $ => parens(
    $,
    optional(sep1(',', choice(field('export', alias($._ie_entity, $.export)), $.module_export))),
    optional(','),
  ),

  // ------------------------------------------------------------------------
  // module body / sections
  // ------------------------------------------------------------------------

  header: $ => seq(
    'module',
    field('module', $.module),
    field('exports', optional($.exports)),
    $._where,
  ),

  imports: $ => seq(semis($, field('import', $.import)), semi($)),

  /**
   * Using `semi` at the end instead of `semi_opt` increases parser size by a full megabyte!!
   *
   * This allows imports after the first declaration to prevent the tree from jittering while typing an import:
   *
   * > import A
   * > imp
   * > import B
   *
   * The partially typed `imp` will be parsed as a `top_splice`, which forces `imports` to reduce after `import A`.
   * The rest of the file will then be part of `declarations` and all following imports will be broken until the keyword
   * has been completed.
   */
  declarations: $ => seq($.declaration, repeat(seq(semi($), choice($.declaration, $.import))), semi_opt($)),

  _body: $ => seq(
    choice($._cmd_layout_start, alias($._cmd_layout_start_explicit, '{')),
    semi_opt($),
    field('imports', optional($.imports)),
    field('declarations', optional($.declarations)),
    $._layout_end,
  ),

  _layout_end: $ => choice(
    $._cond_layout_end,
    alias($._cond_layout_end_explicit, '}'),
  ),

  /**
   * This is a supertype.
   */
  declaration: $ => choice(
    $.decl,
    $.type_synomym,
    $.kind_signature,
    $.type_family,
    $.type_instance,
    $.role_annotation,
    $.data_type,
    $.newtype,
    $.data_family,
    $.data_instance,
    $.class,
    $.instance,
    $.default_types,
    $.deriving_instance,
    $.pattern_synonym,
    $.foreign_import,
    $.foreign_export,
    $.fixity,
    $.top_splice,
  ),

}
