/**
 * Blazor State Validator
 *
 * Validates SessionState patterns in Blazor Server applications.
 * Ensures proper Persist + Reload pattern implementation.
 *
 * @module blazor-state-validator
 */

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

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

// SessionState class patterns
const SESSION_STATE_CLASS_PATTERNS = [
  /class\s+SessionState/,
  /public\s+class\s+\w*Session\w*State/,
  /public\s+class\s+\w*State\w*Session/,
];

// LoadFrom method pattern
const LOAD_FROM_PATTERN = /void\s+LoadFrom|LoadFrom\s*\(/;

// IsLoaded property pattern
const IS_LOADED_PATTERN = /bool\s+IsLoaded|IsLoaded\s*\{/;

// Session middleware patterns
const SESSION_MIDDLEWARE_PATTERNS = [
  /SessionMiddleware/,
  /UseSessionTracking/,
  /X-Session-Id/,
  /SessionId/,
];

// OnInitializedAsync with session reload pattern
const ON_INITIALIZED_RELOAD_PATTERN = /OnInitializedAsync.*Session.*LoadFrom|Session\.IsLoaded/s;

/**
 * Validates SessionState class implementation.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {StateIssue[]}
 */
export function validateSessionStateClass(content, filePath) {
  const issues = [];

  // Check if this is a SessionState class
  const isSessionStateClass = SESSION_STATE_CLASS_PATTERNS.some((pattern) =>
    pattern.test(content)
  );

  if (!isSessionStateClass) {
    return issues;
  }

  // Check for LoadFrom method
  if (!LOAD_FROM_PATTERN.test(content)) {
    issues.push({
      type: 'error',
      message: 'SessionState sem metodo LoadFrom()',
      suggestion:
        'Adicione um metodo LoadFrom(entity) para carregar estado do banco. Ver framework/standards/frontend/blazor/state.md',
      file: filePath,
    });
  }

  // Check for IsLoaded property
  if (!IS_LOADED_PATTERN.test(content)) {
    issues.push({
      type: 'warning',
      message: 'SessionState sem propriedade IsLoaded',
      suggestion:
        'Adicione propriedade IsLoaded para evitar reloads desnecessarios',
      file: filePath,
    });
  }

  // Check for ToEntity method
  if (!content.includes('ToEntity')) {
    issues.push({
      type: 'info',
      message: 'SessionState sem metodo ToEntity()',
      suggestion:
        'Considere adicionar ToEntity() para facilitar persistencia',
      file: filePath,
    });
  }

  return issues;
}

/**
 * Validates Program.cs for session middleware setup.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {StateIssue[]}
 */
export function validateProgramCsSetup(content, filePath) {
  const issues = [];

  // Only check Program.cs
  if (!filePath.toLowerCase().includes('program.cs')) {
    return issues;
  }

  // Check if project uses SessionState
  if (!content.includes('SessionState') && !content.includes('ISessionRepository')) {
    return issues; // Project doesn't seem to use session state
  }

  // Check for session middleware
  const hasSessionMiddleware = SESSION_MIDDLEWARE_PATTERNS.some((pattern) =>
    pattern.test(content)
  );

  if (!hasSessionMiddleware) {
    issues.push({
      type: 'warning',
      message: 'SessionMiddleware nao encontrado em Program.cs',
      suggestion:
        'Adicione app.UseSessionTracking() antes de UseRouting(). Ver framework/standards/frontend/blazor/state.md',
      file: filePath,
    });
  }

  // Check for IHttpContextAccessor
  if (!content.includes('AddHttpContextAccessor')) {
    issues.push({
      type: 'warning',
      message: 'IHttpContextAccessor nao registrado',
      suggestion:
        'Adicione builder.Services.AddHttpContextAccessor() para acessar SessionId em componentes',
      file: filePath,
    });
  }

  return issues;
}

/**
 * Validates Blazor pages for session reload pattern.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {StateIssue[]}
 */
export function validatePageSessionReload(content, filePath) {
  const issues = [];

  // Only check .razor files
  if (!filePath.endsWith('.razor')) {
    return issues;
  }

  // Check if page uses SessionState
  const usesSessionState =
    content.includes('SessionState') ||
    content.includes('@inject SessionState') ||
    content.includes('[Inject] SessionState');

  if (!usesSessionState) {
    return issues;
  }

  // Check for OnInitializedAsync
  if (!content.includes('OnInitializedAsync')) {
    issues.push({
      type: 'warning',
      message: 'Pagina usa SessionState mas nao tem OnInitializedAsync',
      suggestion:
        'Adicione OnInitializedAsync para verificar e recarregar SessionState',
      file: filePath,
    });
    return issues;
  }

  // Check for IsLoaded check or LoadFrom in OnInitializedAsync
  if (!content.includes('IsLoaded') && !content.includes('LoadFrom')) {
    issues.push({
      type: 'warning',
      message: 'Pagina usa SessionState sem verificar IsLoaded',
      suggestion:
        'Verifique Session.IsLoaded e chame LoadFrom() em OnInitializedAsync se necessario',
      file: filePath,
    });
  }

  return issues;
}

/**
 * Validates session repository implementation.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {StateIssue[]}
 */
export function validateSessionRepository(content, filePath) {
  const issues = [];

  // Check if this is a session repository
  const isSessionRepo =
    content.includes('ISessionRepository') ||
    content.includes('SessionRepository') ||
    content.includes('GetBySessionIdAsync');

  if (!isSessionRepo) {
    return issues;
  }

  // Check for essential methods
  if (!content.includes('GetBySessionIdAsync')) {
    issues.push({
      type: 'error',
      message: 'SessionRepository sem GetBySessionIdAsync',
      suggestion: 'Adicione metodo para buscar sessao por ID',
      file: filePath,
    });
  }

  if (!content.includes('SaveAsync') && !content.includes('UpsertAsync')) {
    issues.push({
      type: 'warning',
      message: 'SessionRepository sem metodo de persistencia (SaveAsync/UpsertAsync)',
      suggestion: 'Adicione metodo para salvar estado da sessao',
      file: filePath,
    });
  }

  // Check for cleanup method
  if (!content.includes('CleanupExpiredAsync') && !content.includes('DeleteExpired')) {
    issues.push({
      type: 'info',
      message: 'SessionRepository sem metodo de limpeza de sessoes expiradas',
      suggestion:
        'Considere adicionar CleanupExpiredAsync() para remover sessoes antigas',
      file: filePath,
    });
  }

  return issues;
}

/**
 * Runs all state validations on a file.
 *
 * @param {string} content - File content
 * @param {string} filePath - Path to the file
 * @returns {StateIssue[]}
 */
export function validateBlazorState(content, filePath) {
  const issues = [];

  issues.push(...validateSessionStateClass(content, filePath));
  issues.push(...validateProgramCsSetup(content, filePath));
  issues.push(...validatePageSessionReload(content, filePath));
  issues.push(...validateSessionRepository(content, filePath));

  return issues;
}

export default {
  validateBlazorState,
  validateSessionStateClass,
  validateProgramCsSetup,
  validatePageSessionReload,
  validateSessionRepository,
  countIssues,
};
