/*
 * Copyright (C) 2023 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {Injectable} from '@angular/core';
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
import {
  SCLanguage,
  SCLanguageCode,
  SCThings,
  SCThingTranslator,
  SCThingType,
  SCTranslations,
} from '@openstapps/core';
import moment from 'moment';
import {isDefined, ThingTranslateParser} from './thing-translate.parser';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {setDefaultOptions} from 'date-fns';
import {DateFnsConfigurationService} from 'ngx-date-fns';
import {getDateFnsLocale} from './dfns-locale';

// export const DEFAULT_LANGUAGE = new InjectionToken<string>('DEFAULT_LANGUAGE');

/* eslint-disable @typescript-eslint/member-ordering, class-methods-use-this, newline-per-chained-call,  */

@Injectable({
  providedIn: 'root',
})
export class ThingTranslateService {
  translator: SCThingTranslator;

  /**
   *
   * @param translateService Instance of Angular TranslateService
   * @param parser An instance of the parser currently used
   * @param dfnsConfiguration the date fns configuration
   */
  constructor(
    private readonly translateService: TranslateService,
    public parser: ThingTranslateParser,
    private dfnsConfiguration: DateFnsConfigurationService,
  ) {
    this.translator = new SCThingTranslator(
      (translateService.currentLang ?? translateService.defaultLang) as SCLanguageCode,
    );
    /** set the default language from configuration */
    this.translateService.onLangChange.pipe(takeUntilDestroyed()).subscribe((event: LangChangeEvent) => {
      this.translator.language = event.lang as keyof SCTranslations<SCLanguage>;
      moment.locale(event.lang);
      getDateFnsLocale(event.lang as SCLanguageCode).then(locale => {
        setDefaultOptions({locale});
        this.dfnsConfiguration.setLocale(locale);
      });
    });
  }

  /**
   * Returns the parsed result of the translations
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/ban-types
  getParsedResult(target: object, key: string): any {
    return this.parser.getValueFromKeyPath(target, key);
  }

  /**
   * Gets the translated value of a key (or an array of keys)
   * @param thing SCThing to get
   * @param keyPath Path to the key
   * @returns the translated key, or an object of translated keys
   */
  public get(
    thing: SCThings,
    keyPath: string | string[],
    // eslint-disable-next-line @typescript-eslint/ban-types
  ): string | number | boolean | object {
    if (!isDefined(keyPath) || keyPath.length === 0) {
      throw new Error(`Parameter "keyPath" required`);
    }
    if (Array.isArray(keyPath)) {
      return this.getParsedResult(this.translator.translate(thing), keyPath.join('.'));
    }

    return this.getParsedResult(this.translator.translate(thing), keyPath);
  }

  /**
   * Gets the translated value of a key (or an array of keys)
   * @param type Type of the property
   * @param keyPath Path to the key
   * @returns the translated key, or an object of translated keys
   */
  public getPropertyName(type: SCThingType, keyPath: string | string[]): string {
    const translatedPropertyNames = this.translator.translatedPropertyNames(type);
    if (!isDefined(translatedPropertyNames)) {
      throw new Error(`Parameter "type" is an invalid SCThingType`);
    }
    if (!isDefined(keyPath) || keyPath.length === 0) {
      throw new Error(`Parameter "keyPath" required`);
    }
    if (Array.isArray(keyPath)) {
      return this.getParsedResult(translatedPropertyNames, keyPath.join('.'));
    }

    return this.getParsedResult(translatedPropertyNames, keyPath);
  }
}
