/**
 * Blazor Validator - Fluent UI Blazor Pattern Validation
 *
 * Validates Blazor/Razor files for common Fluent UI patterns and issues.
 *
 * @module blazor-validator
 */

import { countIssues } from '../shared/index.js';

// Valid icon sizes in Fluent UI Blazor
export const VALID_ICON_SIZES = [20, 24, 28, 32, 48];

// Icons that don't exist and their alternatives
export const ICON_ALTERNATIVES = {
  Compass: 'CompassNorthwest',
  Instagram: 'Camera',
  WhatsApp: 'Chat',
  Facebook: 'Share',
  Twitter: 'Share',
  X: 'Share',
  LinkedIn: 'Person',
};

// Async methods that don't exist in IToastService
export const INVALID_TOAST_METHODS = [
  'ShowSuccessAsync',
  'ShowErrorAsync',
  'ShowWarningAsync',
  'ShowInfoAsync',
];

// Async methods that don't exist in FluentDialog
export const INVALID_DIALOG_METHODS = ['ShowAsync', 'HideAsync'];

/**
 * @typedef {Object} ValidationIssue
 * @property {'error' | 'warning'} type - Severity of the issue
 * @property {string} message - Description of the issue
 * @property {string} [suggestion] - How to fix the issue
 * @property {string} file - File path
 * @property {number} [line] - Line number (1-indexed)
 * @property {string} [code] - The problematic code snippet
 */

/**
 * Validates icon usage in Fluent UI Blazor files.
 * Detects invalid sizes and non-existent icons.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of validation issues
 */
export function validateIconUsage(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  // Pattern: Icons.(Regular|Filled).Size{N}.{IconName}()
  const iconRegex = /Icons\.(Regular|Filled)\.Size(\d+)\.(\w+)\(\)/g;

  lines.forEach((line, index) => {
    const lineNumber = index + 1;
    let match;

    // Reset regex lastIndex for each line
    iconRegex.lastIndex = 0;

    while ((match = iconRegex.exec(line)) !== null) {
      const [fullMatch, type, sizeStr, iconName] = match;
      const size = parseInt(sizeStr, 10);

      // Check for invalid size
      if (!VALID_ICON_SIZES.includes(size)) {
        issues.push({
          type: 'error',
          message: `Icons.${type}.Size${size} - Size${size} nao e valido`,
          suggestion: `Use Size20, Size24, Size28, Size32 ou Size48`,
          file: filePath,
          line: lineNumber,
          code: fullMatch,
        });
      }

      // Check for non-existent icons
      if (ICON_ALTERNATIVES[iconName]) {
        issues.push({
          type: 'error',
          message: `Icons.${type}.Size${size}.${iconName} - Icone nao existe`,
          suggestion: `Use ${ICON_ALTERNATIVES[iconName]} como alternativa`,
          file: filePath,
          line: lineNumber,
          code: fullMatch,
        });
      }
    }
  });

  return issues;
}

/**
 * Validates FluentDialog patterns.
 * Detects missing Hidden="true" and invalid async methods.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of validation issues
 */
export function validateDialogPatterns(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  lines.forEach((line, index) => {
    const lineNumber = index + 1;

    // Check for FluentDialog without Hidden="true"
    // Match <FluentDialog that has @ref but no Hidden="true"
    if (line.includes('<FluentDialog') && !line.includes('Hidden=')) {
      // Check if it's a self-closing tag or opening tag
      if (line.includes('@ref=') || line.includes('Modal=')) {
        issues.push({
          type: 'warning',
          message: `FluentDialog sem Hidden="true" - modal sera visivel ao carregar`,
          suggestion: `Adicione Hidden="true" ao FluentDialog`,
          file: filePath,
          line: lineNumber,
          code: line.trim(),
        });
      }
    }

    // Check for invalid async methods
    INVALID_DIALOG_METHODS.forEach((method) => {
      if (line.includes(`_dialog.${method}`) || line.includes(`.${method}(`)) {
        if (line.includes('dialog') || line.includes('Dialog')) {
          issues.push({
            type: 'error',
            message: `FluentDialog.${method}() nao existe`,
            suggestion:
              method === 'ShowAsync'
                ? `Use Show() (sincrono)`
                : `Use CloseAsync() em vez de HideAsync()`,
            file: filePath,
            line: lineNumber,
            code: line.trim(),
          });
        }
      }
    });
  });

  return issues;
}

/**
 * Validates Toast Service usage.
 * Detects non-existent async methods.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of validation issues
 */
export function validateToastUsage(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  lines.forEach((line, index) => {
    const lineNumber = index + 1;

    INVALID_TOAST_METHODS.forEach((method) => {
      if (line.includes(method)) {
        const syncMethod = method.replace('Async', '');
        issues.push({
          type: 'error',
          message: `ToastService.${method}() nao existe`,
          suggestion: `Use ToastService.${syncMethod}() (sincrono)`,
          file: filePath,
          line: lineNumber,
          code: line.trim(),
        });
      }
    });
  });

  return issues;
}

/**
 * Validates Icon namespace usage.
 * Detects missing alias requirement.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of validation issues
 */
export function validateNamespaceAlias(content, filePath) {
  const issues = [];
  const lines = content.split('\n');

  // Check if using icons without alias
  const usesIcons =
    content.includes('Icons.Regular') || content.includes('Icons.Filled');

  if (usesIcons) {
    // Check for proper alias
    const hasCorrectAlias = content.includes(
      '@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons'
    );

    // Check for incorrect using (without alias)
    const hasIncorrectUsing =
      content.includes('@using Microsoft.FluentUI.AspNetCore.Components.Icons') &&
      !hasCorrectAlias;

    if (hasIncorrectUsing) {
      // Find the line with the incorrect using
      lines.forEach((line, index) => {
        if (
          line.includes('@using Microsoft.FluentUI.AspNetCore.Components.Icons') &&
          !line.includes('Icons =')
        ) {
          issues.push({
            type: 'error',
            message: `Namespace de Icons sem alias`,
            suggestion: `Use @using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons`,
            file: filePath,
            line: index + 1,
            code: line.trim(),
          });
        }
      });
    }

    // Check if uses icons but has no using at all (might be in _Imports.razor)
    if (
      !hasCorrectAlias &&
      !hasIncorrectUsing &&
      !content.includes('@using Icons =')
    ) {
      // This is just informational - might be defined in _Imports.razor
      // Don't flag as error, but could be a warning
    }
  }

  return issues;
}

/**
 * Validates FluentToastProvider and FluentDialogProvider presence.
 * Only checks layout files.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of validation issues
 */
export function validateProviders(content, filePath) {
  const issues = [];
  const isLayout =
    filePath.toLowerCase().includes('layout') ||
    filePath.toLowerCase().includes('app.razor');

  if (!isLayout) {
    return issues;
  }

  if (
    content.includes('FluentDialog') &&
    !content.includes('<FluentDialogProvider')
  ) {
    issues.push({
      type: 'warning',
      message: `FluentDialogProvider nao encontrado no layout`,
      suggestion: `Adicione <FluentDialogProvider /> ao layout`,
      file: filePath,
      line: 1,
    });
  }

  if (
    content.includes('ToastService') &&
    !content.includes('<FluentToastProvider')
  ) {
    issues.push({
      type: 'warning',
      message: `FluentToastProvider nao encontrado no layout`,
      suggestion: `Adicione <FluentToastProvider /> ao layout`,
      file: filePath,
      line: 1,
    });
  }

  return issues;
}

/**
 * Runs all validations on a Blazor file.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {ValidationIssue[]} Array of all validation issues
 */
export function validateBlazorFile(content, filePath) {
  const issues = [];

  issues.push(...validateIconUsage(content, filePath));
  issues.push(...validateDialogPatterns(content, filePath));
  issues.push(...validateToastUsage(content, filePath));
  issues.push(...validateNamespaceAlias(content, filePath));
  issues.push(...validateProviders(content, filePath));

  return issues;
}

/**
 * Formats validation issues for console output.
 *
 * @param {ValidationIssue[]} issues - Array of validation issues
 * @returns {string} Formatted output string
 */
export function formatIssues(issues) {
  if (issues.length === 0) {
    return '';
  }

  const lines = [];

  issues.forEach((issue) => {
    const icon = issue.type === 'error' ? '\u274C' : '\u26A0\uFE0F';
    const label = issue.type === 'error' ? 'Error' : 'Warning';

    lines.push(`${icon} ${label}: ${issue.message}`);

    if (issue.suggestion) {
      lines.push(`   Sugestao: ${issue.suggestion}`);
    }

    const location = issue.line ? `${issue.file}:${issue.line}` : issue.file;
    lines.push(`   Arquivo: ${location}`);

    if (issue.code) {
      lines.push(`   Codigo: ${issue.code}`);
    }

    lines.push('');
  });

  return lines.join('\n');
}

/**
 * Counts issues by type.
 *
 * @param {ValidationIssue[]} issues - Array of validation issues
 * @returns {{ errors: number, warnings: number }} Count by type
 */
export default {
  VALID_ICON_SIZES,
  ICON_ALTERNATIVES,
  INVALID_TOAST_METHODS,
  INVALID_DIALOG_METHODS,
  validateIconUsage,
  validateDialogPatterns,
  validateToastUsage,
  validateNamespaceAlias,
  validateProviders,
  validateBlazorFile,
  formatIssues,
  countIssues,
};
