import type { IDomainValidationService } from '@core/shared/domain';
import { Result } from '@gridpilot/shared/application/Result';

/**
 * Configuration for page state validation.
 * Defines expected and forbidden elements on the current page.
 */
export interface PageStateValidation {
  /** Expected wizard step name (e.g., 'cars', 'track') */
  expectedStep: string;
  /** Selectors that MUST be present on the page */
  requiredSelectors: string[];
  /** Selectors that MUST NOT be present on the page */
  forbiddenSelectors?: string[];
}

/**
 * Result of page state validation.
 */
export interface PageStateValidationResult {
  isValid: boolean;
  message: string;
  expectedStep: string;
  missingSelectors?: string[];
  unexpectedSelectors?: string[];
}

export interface PageStateValidationInput {
  actualState: (_selector: string) => boolean;
  validation: PageStateValidation;
  realMode?: boolean;
}

/**
 * Domain service for validating page state during wizard navigation.
 *
 * Purpose: Prevent navigation bugs by ensuring each step executes on the correct page.
 *
 * Clean Architecture: This is pure domain logic with no infrastructure dependencies.
 * It validates state based on selector presence/absence without knowing HOW to check them.
 */
export class PageStateValidator
  implements
    IDomainValidationService<PageStateValidationInput, PageStateValidationResult, Error>
{
  validate(input: PageStateValidationInput): Result<PageStateValidationResult, Error> {
    const { actualState, validation, realMode } = input;
    if (typeof realMode === 'boolean') {
      return this.validateStateEnhanced(actualState, validation, realMode);
    }
    return this.validateState(actualState, validation);
  }

  /**
   * Validate that the page state matches expected conditions.
   *
   * @param actualState Function that checks if selectors exist on the page
   * @param validation Expected page state configuration
   * @returns Result with validation outcome
   */
  validateState(
    actualState: (_selector: string) => boolean,
    validation: PageStateValidation
  ): Result<PageStateValidationResult, Error> {
    try {
      const { expectedStep, requiredSelectors, forbiddenSelectors = [] } = validation;

      // Check required selectors are present
      const missingSelectors = requiredSelectors.filter(_selector => !actualState(_selector));

      if (missingSelectors.length > 0) {
        const result: PageStateValidationResult = {
          isValid: false,
          message: `Page state mismatch: Expected to be on "${expectedStep}" page but missing required elements`,
          expectedStep,
          missingSelectors
        };
        return Result.ok(result);
      }

      // Check forbidden selectors are absent
      const unexpectedSelectors = forbiddenSelectors.filter(_selector => actualState(_selector));

      if (unexpectedSelectors.length > 0) {
        const result: PageStateValidationResult = {
          isValid: false,
          message: `Page state mismatch: Found unexpected elements on "${expectedStep}" page`,
          expectedStep,
          unexpectedSelectors
        };
        return Result.ok(result);
      }

      // All checks passed
      const result: PageStateValidationResult = {
        isValid: true,
        message: `Page state valid for "${expectedStep}"`,
        expectedStep
      };
      return Result.ok(result);
    } catch (error) {
      return Result.err(
        error instanceof Error
          ? error
          : new Error(`Page state validation failed: ${String(error)}`)
      );
    }
  }

  /**
   * Enhanced validation that tries multiple selector strategies for real iRacing HTML.
   * This handles the mismatch between test expectations (data-indicator attributes)
   * and real HTML structure (Chakra UI components).
   *
   * @param actualState Function that checks if selectors exist on the page
   * @param validation Expected page state configuration
   * @param realMode Whether we're in real mode (using real HTML dumps) or mock mode
   * @returns Result with validation outcome
   */
  validateStateEnhanced(
    actualState: (_selector: string) => boolean,
    validation: PageStateValidation,
    realMode: boolean = false
  ): Result<PageStateValidationResult, Error> {
    try {
      const { expectedStep, requiredSelectors, forbiddenSelectors = [] } = validation;

      // In real mode, try to match the actual HTML structure with fallbacks
      let selectorsToCheck = [...requiredSelectors];

      if (realMode) {
        // Add fallback selectors for real iRacing HTML (Chakra UI structure)
        const fallbackMap: Record<string, string[]> = {
          cars: [
            '#set-cars',
            '[id*="cars"]',
            '.wizard-step[id*="cars"]',
            '.cars-panel',
            // Real iRacing fallbacks - use step container IDs
            '[data-testid*="set-cars"]',
            '.chakra-stack:has([data-testid*="cars"])',
          ],
          track: [
            '#set-track',
            '[id*="track"]',
            '.wizard-step[id*="track"]',
            '.track-panel',
            // Real iRacing fallbacks
            '[data-testid*="set-track"]',
            '.chakra-stack:has([data-testid*="track"])',
          ],
          'add-car': [
            'a.btn:has-text("Add a Car")',
            '.btn:has-text("Add a Car")',
            '[data-testid*="add-car"]',
            // Real iRacing button selectors
            'a.btn.btn-primary.btn-block.btn-sm:has-text("Add a Car")',
          ],
        };

        // For each required selector, add fallbacks
        const enhancedSelectors: string[] = [];
        for (const selector of requiredSelectors) {
          enhancedSelectors.push(selector);

          // Add step-specific fallbacks
          const lowerStep = expectedStep.toLowerCase();
          if (fallbackMap[lowerStep]) {
            enhancedSelectors.push(...fallbackMap[lowerStep]);
          }

          // Generic Chakra UI fallbacks for wizard steps
          if (selector.includes('data-indicator')) {
            enhancedSelectors.push(
              `[id*="${expectedStep}"]`,
              `[data-testid*="${expectedStep}"]`,
              `.wizard-step:has([data-testid*="${expectedStep}"])`,
            );
          }
        }

        selectorsToCheck = enhancedSelectors;
      }

      // Check required selectors are present (with fallbacks for real mode)
      const missingSelectors = requiredSelectors.filter(selector => {
        if (realMode) {
          const relatedSelectors = selectorsToCheck.filter(s =>
            s.includes(expectedStep) ||
            s.includes(
              selector
                .replace(/[\[\]"']/g, '')
                .replace('data-indicator=', ''),
            ),
          );
          if (relatedSelectors.length === 0) {
            return !actualState(selector);
          }
          return !relatedSelectors.some(s => actualState(s));
        }
        return !actualState(selector);
      });

      if (missingSelectors.length > 0) {
        const result: PageStateValidationResult = {
          isValid: false,
          message: `Page state mismatch: Expected to be on "${expectedStep}" page but missing required elements`,
          expectedStep,
          missingSelectors
        };
        return Result.ok(result);
      }

      // Check forbidden selectors are absent
      const unexpectedSelectors = forbiddenSelectors.filter(_selector => actualState(_selector));

      if (unexpectedSelectors.length > 0) {
        const result: PageStateValidationResult = {
          isValid: false,
          message: `Page state mismatch: Found unexpected elements on "${expectedStep}" page`,
          expectedStep,
          unexpectedSelectors
        };
        return Result.ok(result);
      }

      // All checks passed
      const result: PageStateValidationResult = {
        isValid: true,
        message: `Page state valid for "${expectedStep}"`,
        expectedStep
      };
      return Result.ok(result);
    } catch (error) {
      return Result.err(
        error instanceof Error
          ? error
          : new Error(`Page state validation failed: ${String(error)}`)
      );
    }
  }
}