import { Injectable } from '@angular/core';
import { FieldSchema } from './field-schema.model';
import { ALL_FIELD_SCHEMAS, SECTION_FIELD_SCHEMAS } from './editor-schema';
import { ProjectEditorSectionId } from '../models/project-editor.model';

/**
 * Read-only accessor over the field-schema registry. The single source of
 * truth for which fields exist, how they are labelled, and which validators
 * apply. Consumed by the validator engine (issue -> field mapping) and by the
 * facade (modified-field diffing).
 */
@Injectable({ providedIn: 'root' })
export class EditorSchemaService {
  private readonly byKey = new Map<string, FieldSchema>(
    // First definition wins; a key may appear under two sections (e.g.
    // localization.supportedLocales in general + languages) - both point at the
    // same underlying config path, so either schema entry resolves it.
    ALL_FIELD_SCHEMAS.map((field): [string, FieldSchema] => [field.key, field]).reverse(),
  );

  /** All fields declared for a section (empty array for unknown sections). */
  getFields(section: ProjectEditorSectionId): readonly FieldSchema[] {
    return SECTION_FIELD_SCHEMAS[section] ?? [];
  }

  /** Lookup a single field by its dot-path key. */
  getField(key: string): FieldSchema | undefined {
    return this.byKey.get(key);
  }

  /** Every field across every section. */
  all(): readonly FieldSchema[] {
    return ALL_FIELD_SCHEMAS;
  }

  /**
   * Resolve a dot-path key against an object, e.g.
   * `getByPath(bootstrap, 'theme.palette.primary')`. Returns `undefined` when
   * any segment is missing rather than throwing.
   */
  getByPath(source: unknown, key: string): unknown {
    return key.split('.').reduce<unknown>((value, segment) => {
      if (value === null || value === undefined || typeof value !== 'object') {
        return undefined;
      }
      return (value as Record<string, unknown>)[segment];
    }, source);
  }
}
