import type { Tree } from '@nx/devkit';
import { joinPathFragments, offsetFromRoot, writeJson } from '@nx/devkit';
import type { Linter } from 'eslint';
import type { AddLintingGeneratorSchema } from '../schema';
import { camelize, dasherize } from '@nx/devkit/src/utils/string-utils';

type EslintExtensionSchema = {
  prefix: string;
};

export const extendAngularEslintJson = (
  json: Linter.Config,
  options: EslintExtensionSchema
) => {
  const overrides = [
    {
      ...json.overrides[0],
      files: ['*.ts'],
      extends: [
        ...(json.overrides[0].extends || []),
        'plugin:@nx/angular',
        'plugin:@angular-eslint/template/process-inline-templates',
      ],
      rules: {
        '@angular-eslint/directive-selector': [
          'error',
          {
            type: 'attribute',
            prefix: camelize(options.prefix),
            style: 'camelCase',
          },
        ],
        '@angular-eslint/component-selector': [
          'error',
          {
            type: 'element',
            prefix: dasherize(options.prefix),
            style: 'kebab-case',
          },
        ],
      },
    },
    {
      files: ['*.html'],
      extends: ['plugin:@nx/angular-template'],
      /**
       * Having an empty rules object present makes it more obvious to the user where they would
       * extend things from if they needed to
       */
      rules: {},
    },
  ];

  return {
    ...json,
    overrides,
  };
};

/**
 * @deprecated Use {@link extendAngularEslintJson} instead
 */
export function createEsLintConfiguration(
  tree: Tree,
  options: AddLintingGeneratorSchema
): void {
  const rootConfig = `${offsetFromRoot(options.projectRoot)}.eslintrc.json`;
  // Include all project files to be linted (since they are turned off in the root eslintrc file).
  const ignorePatterns = ['!**/*'];

  const configJson = {
    extends: [rootConfig],
    ignorePatterns,
    overrides: [
      {
        files: ['*.ts'],
        extends: [
          'plugin:@nx/angular',
          'plugin:@angular-eslint/template/process-inline-templates',
        ],
        /**
         * NOTE: We no longer set parserOptions.project by default when creating new projects.
         *
         * We have observed that users rarely add rules requiring type-checking to their Nx workspaces, and therefore
         * do not actually need the capabilites which parserOptions.project provides. When specifying parserOptions.project,
         * typescript-eslint needs to create full TypeScript Programs for you. When omitting it, it can perform a simple
         * parse (and AST tranformation) of the source files it encounters during a lint run, which is much faster and much
         * less memory intensive.
         *
         * In the rare case that users attempt to add rules requiring type-checking to their setup later on (and haven't set
         * parserOptions.project), the executor will attempt to look for the particular error typescript-eslint gives you
         * and provide feedback to the user.
         */
        parserOptions: !options.setParserOptionsProject
          ? undefined
          : {
              project: [`${options.projectRoot}/tsconfig.*?.json`],
            },
        rules: {
          '@angular-eslint/directive-selector': [
            'error',
            {
              type: 'attribute',
              prefix: camelize(options.prefix),
              style: 'camelCase',
            },
          ],
          '@angular-eslint/component-selector': [
            'error',
            {
              type: 'element',
              prefix: dasherize(options.prefix),
              style: 'kebab-case',
            },
          ],
        },
      },
      {
        files: ['*.html'],
        extends: ['plugin:@nx/angular-template'],
        /**
         * Having an empty rules object present makes it more obvious to the user where they would
         * extend things from if they needed to
         */
        rules: {},
      },
    ],
  };

  writeJson(
    tree,
    joinPathFragments(options.projectRoot, '.eslintrc.json'),
    configJson
  );
}
