export type IntentTargetType = 'agent' | 'skill';

export interface IntentTarget {
  type: IntentTargetType;
  name: string;
}

export interface IntentRule {
  name: string;
  patterns: string[];
  target: IntentTarget;
  priority: number;
  enabled: boolean;
}

export interface IntentMatch {
  rule: IntentRule;
  score: number;
  matchedPattern: string;
}

export interface ComponentRegistryConfig {
  matchThreshold: number;
}

export class ComponentRegistry {
  private readonly matchThreshold: number;
  private readonly rules: IntentRule[] = [];

  constructor(config: ComponentRegistryConfig) {
    this.matchThreshold = config.matchThreshold;
  }

  register(rule: IntentRule): void {
    this.rules.push(rule);
  }

  loadRules(rules: IntentRule[]): void {
    for (const rule of rules) {
      this.register(rule);
    }
  }

  list(): IntentRule[] {
    return [...this.rules];
  }

  match(input: string): IntentMatch | null {
    const normalizedInput = input.trim().toLowerCase();
    if (!normalizedInput) {
      return null;
    }

    let best: { match: IntentMatch; specificity: number } | null = null;

    for (const rule of this.rules) {
      if (!rule.enabled) {
        continue;
      }

      let bestPatternScore = 0;
      let bestPattern = '';
      let bestSpecificity = 0;

      for (const pattern of rule.patterns) {
        const patternResult = this.scorePattern(pattern, normalizedInput);
        if (!patternResult) {
          continue;
        }

        if (patternResult.score > bestPatternScore) {
          bestPatternScore = patternResult.score;
          bestPattern = pattern;
          bestSpecificity = patternResult.specificity;
        }
      }

      if (bestPatternScore < this.matchThreshold) {
        continue;
      }

      const match: IntentMatch = {
        rule,
        score: bestPatternScore,
        matchedPattern: bestPattern,
      };

      if (!best) {
        best = { match, specificity: bestSpecificity };
        continue;
      }

      if (match.score > best.match.score) {
        best = { match, specificity: bestSpecificity };
        continue;
      }

      if (match.score === best.match.score) {
        if (rule.priority > best.match.rule.priority) {
          best = { match, specificity: bestSpecificity };
          continue;
        }

        if (rule.priority === best.match.rule.priority && bestSpecificity > best.specificity) {
          best = { match, specificity: bestSpecificity };
        }
      }
    }

    return best?.match ?? null;
  }

  private scorePattern(pattern: string, normalizedInput: string): { score: number; specificity: number } | null {
    const normalizedPattern = pattern.trim().toLowerCase();
    if (!normalizedPattern) {
      return null;
    }

    const wildcardCount = (normalizedPattern.match(/\*/g) ?? []).length;
    const literalLength = normalizedPattern.replace(/\*/g, '').length;
    const specificity = literalLength / Math.max(normalizedInput.length, 1);

    if (wildcardCount === 0) {
      if (normalizedInput === normalizedPattern) {
        return { score: 1, specificity };
      }
      if (normalizedInput.includes(normalizedPattern)) {
        return { score: Math.min(0.9 + specificity * 0.1, 1), specificity };
      }
      return null;
    }

    const escaped = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
    const regexPattern = escaped.replace(/\*/g, '.*');
    const regex = new RegExp(`^${regexPattern}$`);
    if (!regex.test(normalizedInput)) {
      return null;
    }

    return { score: Math.min(0.8 + specificity * 0.15, 0.99), specificity };
  }
}
