/**
 * lint-fluent command
 *
 * Lints Fluent UI patterns for common issues beyond icons.
 * Focuses on structural patterns in layouts and components.
 *
 * Usage:
 *   morph-spec lint-fluent [path]
 *   morph-spec lint-fluent src/Components --verbose
 */

import { glob } from 'glob';
import { readFileSync, existsSync, statSync } from 'fs';
import { join, resolve, basename } from 'path';
import chalk from 'chalk';
import ora from 'ora';

/**
 * @typedef {Object} LintIssue
 * @property {'error' | 'warning' | 'info'} type
 * @property {string} message
 * @property {string} [suggestion]
 * @property {string} file
 * @property {number} [line]
 */

/**
 * Checks for FluentToastProvider in layout files.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function checkToastProvider(content, filePath) {
  const issues = [];
  const fileName = basename(filePath).toLowerCase();
  const isLayout =
    fileName.includes('layout') ||
    fileName === 'app.razor' ||
    fileName === 'routes.razor';

  if (!isLayout) return issues;

  // Check if uses toast but doesn't have provider
  const usesToast =
    content.includes('IToastService') || content.includes('ToastService');

  if (!content.includes('<FluentToastProvider') && !content.includes('<FluentToastContainer')) {
    if (isLayout) {
      issues.push({
        type: 'warning',
        message: 'FluentToastProvider nao encontrado no layout',
        suggestion:
          'Adicione <FluentToastProvider /> ao MainLayout ou App.razor',
        file: filePath,
      });
    }
  }

  return issues;
}

/**
 * Checks for FluentDialogProvider in layout files.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function checkDialogProvider(content, filePath) {
  const issues = [];
  const fileName = basename(filePath).toLowerCase();
  const isLayout =
    fileName.includes('layout') ||
    fileName === 'app.razor' ||
    fileName === 'routes.razor';

  if (!isLayout) return issues;

  if (!content.includes('<FluentDialogProvider')) {
    issues.push({
      type: 'warning',
      message: 'FluentDialogProvider nao encontrado no layout',
      suggestion:
        'Adicione <FluentDialogProvider /> ao MainLayout ou App.razor',
      file: filePath,
    });
  }

  return issues;
}

/**
 * Checks for @rendermode on FluentDialogProvider.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function checkDialogProviderRenderMode(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  lines.forEach((line, index) => {
    if (line.includes('<FluentDialogProvider')) {
      // Check if it has @rendermode
      if (!line.includes('@rendermode') && !lines[index + 1]?.includes('@rendermode')) {
        issues.push({
          type: 'info',
          message: 'FluentDialogProvider sem @rendermode explicito',
          suggestion:
            'Considere adicionar @rendermode="InteractiveServer" se usar dialogs interativos',
          file: filePath,
          line: index + 1,
        });
      }
    }
  });

  return issues;
}

/**
 * Checks for correct _Imports.razor setup.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function checkImportsRazor(content, filePath) {
  const issues = [];
  const fileName = basename(filePath).toLowerCase();

  if (fileName !== '_imports.razor') return issues;

  // Check for Fluent UI using
  if (!content.includes('@using Microsoft.FluentUI.AspNetCore.Components')) {
    if (
      content.includes('FluentButton') ||
      content.includes('FluentCard') ||
      content.includes('FluentDialog')
    ) {
      issues.push({
        type: 'warning',
        message: 'Fluent UI namespace nao encontrado em _Imports.razor',
        suggestion:
          'Adicione @using Microsoft.FluentUI.AspNetCore.Components',
        file: filePath,
      });
    }
  }

  // Check for Icons alias
  if (
    content.includes('Icons.Regular') ||
    content.includes('Icons.Filled')
  ) {
    if (
      !content.includes(
        '@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons'
      )
    ) {
      issues.push({
        type: 'error',
        message: 'Alias de Icons nao encontrado em _Imports.razor',
        suggestion:
          'Adicione @using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons',
        file: filePath,
      });
    }
  }

  return issues;
}

/**
 * Checks for common FluentDataGrid issues.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function checkDataGridPatterns(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  lines.forEach((line, index) => {
    // Check for large datasets without virtualization
    if (line.includes('<FluentDataGrid') && line.includes('Items=')) {
      // Look for Virtualize in the same tag or next few lines
      const context = lines.slice(index, index + 5).join('\n');
      if (!context.includes('Virtualize=')) {
        issues.push({
          type: 'info',
          message: 'FluentDataGrid sem Virtualize',
          suggestion:
            'Para listas grandes (>100 itens), considere Virtualize="true"',
          file: filePath,
          line: index + 1,
        });
      }
    }
  });

  return issues;
}

/**
 * Runs all lint checks on a file.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {LintIssue[]}
 */
function lintFile(content, filePath) {
  const issues = [];

  issues.push(...checkToastProvider(content, filePath));
  issues.push(...checkDialogProvider(content, filePath));
  issues.push(...checkDialogProviderRenderMode(content, filePath));
  issues.push(...checkImportsRazor(content, filePath));
  issues.push(...checkDataGridPatterns(content, filePath));

  return issues;
}

/**
 * Main command handler for lint-fluent.
 *
 * @param {string} [targetPath] - Path to lint (file or directory)
 * @param {Object} options - Command options
 * @param {boolean} [options.verbose] - Show detailed output
 */
export async function lintFluentCommand(targetPath, options = {}) {
  const { verbose = false } = options;

  console.log('');
  console.log(chalk.cyan('\uD83E\uDDF9 Linting Fluent UI patterns...'));
  console.log('');

  // Determine target path
  const basePath = targetPath ? resolve(targetPath) : process.cwd();

  if (!existsSync(basePath)) {
    console.log(chalk.red(`\u274C Path not found: ${basePath}`));
    process.exit(1);
  }

  const spinner = ora('Scanning for Razor files...').start();

  let files = [];

  try {
    const stats = statSync(basePath);

    if (stats.isFile()) {
      if (basePath.endsWith('.razor')) {
        files = [basePath];
      } else {
        spinner.fail('File must be .razor');
        process.exit(1);
      }
    } else {
      const pattern = join(basePath, '**/*.razor');
      files = await glob(pattern, {
        ignore: ['**/node_modules/**', '**/bin/**', '**/obj/**'],
        windowsPathsNoEscape: true,
      });
    }

    spinner.succeed(`Found ${files.length} Razor file(s)`);
  } catch (error) {
    spinner.fail(`Error scanning files: ${error.message}`);
    process.exit(1);
  }

  if (files.length === 0) {
    console.log(chalk.yellow('\n\u26A0\uFE0F No Razor files found to lint'));
    return;
  }

  // Lint each file
  const allIssues = [];

  for (const file of files) {
    try {
      const content = readFileSync(file, 'utf-8');
      const issues = lintFile(content, file);

      if (issues.length > 0) {
        allIssues.push(...issues);
      }
    } catch (error) {
      console.log(chalk.red(`\u274C Error reading ${file}: ${error.message}`));
    }
  }

  // Output results
  console.log('');

  if (allIssues.length === 0) {
    console.log(chalk.green('\u2705 No lint issues found!'));
    console.log('');
    return;
  }

  // Display issues
  allIssues.forEach((issue) => {
    let icon;
    let color;

    switch (issue.type) {
      case 'error':
        icon = '\u274C';
        color = chalk.red;
        break;
      case 'warning':
        icon = '\u26A0\uFE0F';
        color = chalk.yellow;
        break;
      case 'info':
        icon = '\u2139\uFE0F';
        color = chalk.blue;
        break;
    }

    const location = issue.line ? `${issue.file}:${issue.line}` : issue.file;

    console.log(`${icon} ${color(issue.message)}`);
    if (issue.suggestion) {
      console.log(chalk.gray(`   \u2192 ${issue.suggestion}`));
    }
    console.log(chalk.dim(`   ${location}`));
    console.log('');
  });

  // Summary
  const errors = allIssues.filter((i) => i.type === 'error').length;
  const warnings = allIssues.filter((i) => i.type === 'warning').length;
  const infos = allIssues.filter((i) => i.type === 'info').length;

  console.log(chalk.gray('-'.repeat(60)));
  console.log(
    `\n${files.length} arquivo(s) | ${errors} erro(s) | ${warnings} warning(s) | ${infos} info(s)\n`
  );

  if (errors > 0) {
    process.exit(1);
  }
}

export default lintFluentCommand;
