import { ICalendarEvent } from '../types/CalendarTypes';
import { DateService } from './DateService';
import { IEntityResolver } from './IEntityResolver';

/**
 * Field definition for FilterTemplate
 */
interface IFilterField {
  idProperty: string;
  derivedFrom?: string;
}

/**
 * Parsed dot-notation reference
 */
interface IDotNotation {
  entityType: string;   // e.g., 'resource'
  property: string;     // e.g., 'teamId'
  foreignKey: string;   // e.g., 'resourceId'
}

/**
 * FilterTemplate - Bygger nøgler til event-kolonne matching
 *
 * ViewConfig definerer hvilke felter (idProperties) der indgår i kolonnens nøgle.
 * Samme template bruges til at bygge nøgle for både kolonne og event.
 *
 * Supports dot-notation for hierarchical relations:
 * - 'resource.teamId' → looks up event.resourceId → resource entity → teamId
 *
 * Princip: Kolonnens nøgle-template bestemmer hvad der matches på.
 *
 * @see docs/filter-template.md
 */
export class FilterTemplate {
  private fields: IFilterField[] = [];

  constructor(
    private dateService: DateService,
    private entityResolver?: IEntityResolver
  ) {}

  /**
   * Tilføj felt til template
   * @param idProperty - Property-navn (bruges på både event og column.dataset)
   * @param derivedFrom - Hvis feltet udledes fra anden property (f.eks. date fra start)
   */
  addField(idProperty: string, derivedFrom?: string): this {
    this.fields.push({ idProperty, derivedFrom });
    return this;
  }

  /**
   * Parse dot-notation string into components
   * @example 'resource.teamId' → { entityType: 'resource', property: 'teamId', foreignKey: 'resourceId' }
   */
  private parseDotNotation(idProperty: string): IDotNotation | null {
    if (!idProperty.includes('.')) return null;
    const [entityType, property] = idProperty.split('.');
    return {
      entityType,
      property,
      foreignKey: entityType + 'Id' // Convention: resource → resourceId
    };
  }

  /**
   * Get dataset key for column lookup
   * For dot-notation 'resource.teamId', we look for 'teamId' in dataset
   */
  private getDatasetKey(idProperty: string): string {
    const dotNotation = this.parseDotNotation(idProperty);
    if (dotNotation) {
      return dotNotation.property; // 'teamId'
    }
    return idProperty;
  }

  /**
   * Byg nøgle fra kolonne
   * Læser værdier fra column.dataset[idProperty]
   * For dot-notation, uses the property part (resource.teamId → teamId)
   */
  buildKeyFromColumn(column: HTMLElement): string {
    return this.fields
      .map(f => {
        const key = this.getDatasetKey(f.idProperty);
        return column.dataset[key] || '';
      })
      .join(':');
  }

  /**
   * Byg nøgle fra event
   * Læser værdier fra event[idProperty] eller udleder fra derivedFrom
   * For dot-notation, resolves via EntityResolver
   */
  buildKeyFromEvent(event: ICalendarEvent): string {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const eventRecord = event as any;
    return this.fields
      .map(f => {
        // Check for dot-notation (e.g., 'resource.teamId')
        const dotNotation = this.parseDotNotation(f.idProperty);
        if (dotNotation) {
          return this.resolveDotNotation(eventRecord, dotNotation);
        }

        if (f.derivedFrom) {
          // Udled værdi (f.eks. date fra start)
          const sourceValue = eventRecord[f.derivedFrom];
          if (sourceValue instanceof Date) {
            return this.dateService.getDateKey(sourceValue);
          }
          return String(sourceValue || '');
        }
        return String(eventRecord[f.idProperty] || '');
      })
      .join(':');
  }

  /**
   * Resolve dot-notation reference via EntityResolver
   */
  private resolveDotNotation(eventRecord: Record<string, unknown>, dotNotation: IDotNotation): string {
    if (!this.entityResolver) {
      console.warn(`FilterTemplate: EntityResolver required for dot-notation '${dotNotation.entityType}.${dotNotation.property}'`);
      return '';
    }

    // Get foreign key value from event (e.g., resourceId)
    const foreignId = eventRecord[dotNotation.foreignKey];
    if (!foreignId) return '';

    // Resolve entity
    const entity = this.entityResolver.resolve(dotNotation.entityType, String(foreignId));
    if (!entity) return '';

    // Return property value from entity
    return String(entity[dotNotation.property] || '');
  }

  /**
   * Match event mod kolonne
   */
  matches(event: ICalendarEvent, column: HTMLElement): boolean {
    return this.buildKeyFromEvent(event) === this.buildKeyFromColumn(column);
  }
}
