/**
 * Extensible resource validation framework.
 *
 * Services register rules that validate resource data before create/update.
 * Each rule targets a resource kind and optionally matches on specific
 * instances (e.g., system prompts only). The registry aggregates errors
 * from all matching rules.
 */

export interface ResourceRule<T = unknown> {
  /** Rule identifier for error messages. */
  name: string;
  /** Resource kind this rule applies to: 'prompt', 'server', 'project', etc. */
  resource: string;
  /** Does this rule apply to the given resource instance? */
  match(data: T, meta: RuleMeta): boolean;
  /** Validate the resource data. */
  validate(data: T, ctx: RuleContext): Promise<ValidationResult>;
}

export interface RuleMeta {
  projectName?: string | undefined;
  isSystemResource?: boolean | undefined;
  operation: 'create' | 'update';
}

export interface RuleContext {
  /** Cross-resource lookups (e.g., check if a secret exists). */
  findResource(kind: string, name: string): Promise<unknown | null>;
}

export interface ValidationResult {
  valid: boolean;
  errors?: string[];
}

/**
 * Registry holding all resource validation rules.
 * Services call `validate()` which runs all matching rules and aggregates errors.
 */
export class ResourceRuleRegistry {
  private rules: ResourceRule[] = [];

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

  async validate<T>(
    resource: string,
    data: T,
    meta: RuleMeta,
    ctx: RuleContext,
  ): Promise<ValidationResult> {
    const allErrors: string[] = [];

    for (const rule of this.rules) {
      if (rule.resource !== resource) continue;
      if (!rule.match(data as never, meta)) continue;

      const result = await rule.validate(data as never, ctx);
      if (!result.valid && result.errors) {
        allErrors.push(...result.errors);
      }
    }

    if (allErrors.length > 0) {
      return { valid: false, errors: allErrors };
    }
    return { valid: true };
  }
}
