// Copyright 2025 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Prefer `urlString` helper over sprinkling casts to
 * `UrlString` across the codebase..
 */

import type {TSESLint, TSESTree} from '@typescript-eslint/utils';

import {createRule} from './utils/ruleCreator.ts';

// Define specific node types for clarity
type ImportDeclaration = TSESTree.ImportDeclaration;
type TSAsExpression = TSESTree.TSAsExpression;
type TSTypeReference = TSESTree.TSTypeReference;
type RuleFix = TSESLint.RuleFix;

export default createRule({
  name: 'prefer-url-string',
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Prefer `urlString` helper over manual casts to `UrlString` branded type.',
      category: 'Best Practices',
    },
    messages: {
      useUrlString: 'Use `urlString` helper instead of explicitly casting strings to the `UrlString` branded type',
    },
    fixable: 'code',
    schema: [],  // no options
  },
  defaultOptions: [],
  create: function(context) {
    const sourceCode = context.sourceCode;
    let lastImportNode: ImportDeclaration|null = null;
    let importTypeStarAsPlatformNode: ImportDeclaration|null = null;

    function isImportTypeStarAsPlatform(node: ImportDeclaration): boolean {
      return node.importKind === 'type' && node.specifiers.length === 1 &&
          node.specifiers[0].type === 'ImportNamespaceSpecifier' && node.specifiers[0].local.type === 'Identifier' &&
          node.specifiers[0].local.name === 'Platform';
    }

    function isPlatformDevToolsPathUrlString(node: TSESTree.TypeNode): node is TSTypeReference {
      // Check if it's a TSTypeReference with a TSQualifiedName
      if (node.type !== 'TSTypeReference' || node.typeName.type !== 'TSQualifiedName') {
        return false;
      }

      const typeName = node.typeName;
      // Check Platform.DevToolsPath part
      if (typeName.left.type !== 'TSQualifiedName' || typeName.left.left.type !== 'Identifier' ||
          typeName.left.left.name !== 'Platform' || typeName.left.right.type !== 'Identifier' ||
          typeName.left.right.name !== 'DevToolsPath') {
        return false;
      }

      // Check UrlString part
      return typeName.right.type === 'Identifier' && typeName.right.name === 'UrlString';
    }

    function reportError(node: TSAsExpression) {
      context.report({
        node,
        messageId: 'useUrlString',
        fix(fixer) {
          const urlText = node.expression.type === 'Literal' ?
              String(node.expression.value).replace('$', '\\$').replace('`', '\\`') :
              `\${${sourceCode.getText(node.expression)}}`;
          const nodeText = `urlString\`${urlText}\``;
          const fixers: RuleFix[] = [fixer.replaceText(node, nodeText)];

          // Add import fix if needed
          if (lastImportNode !== null) {
            fixers.push(fixer.insertTextAfter(lastImportNode, '\n\nconst {urlString} = Platform.DevToolsPath;'));
            // Prevent adding the import fix multiple times within the same file run
            lastImportNode = null;
          }

          // Modify type import if needed
          if (importTypeStarAsPlatformNode) {
            const importStarAsPlatformText =
                sourceCode.getText(importTypeStarAsPlatformNode).replace(/import\s+type/, 'import');
            fixers.push(fixer.replaceText(importTypeStarAsPlatformNode, importStarAsPlatformText));
            // Prevent modifying the import multiple times
            importTypeStarAsPlatformNode = null;
          }
          return fixers;
        },
      });
    }

    return {
      ImportDeclaration(node) {
        lastImportNode = node;
        if (isImportTypeStarAsPlatform(node)) {
          importTypeStarAsPlatformNode = node;
        }
      },
      TSAsExpression(node) {
        if (isPlatformDevToolsPathUrlString(node.typeAnnotation)) {
          reportError(node);
        }
      },
    };
  },
});
