/*
 * 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 {Component, Input} from '@angular/core';
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
import {SCLanguage, SCThingTranslator, SCThingType, SCTranslations} from '@openstapps/core';
import {ContextMenuService} from './context-menu.service';
import {FilterContext, FilterFacet, SortContext, SortContextOption} from './context-type.js';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';

/**
 * The context menu
 *
 * It can be configured with sorting types and filtering on facets
 *
 * Example:<br>
 *  `<stapps-context (optionChange)="onOptionChange($event)" (settingChange)="onSettingChange($event)"
 *  [sortOption]="SortContext" [filterOption]="FilterContext"></stapps-context>`
 */
@Component({
  selector: 'stapps-context',
  templateUrl: 'context-menu.html',
})
export class ContextMenuComponent {
  /**
   * Id of the content the menu is used for
   */
  @Input()
  contentId: string;

  /**
   * Amount of filter options shown on compact view
   */
  compactFilterOptionCount = 5;

  /**
   * Container for the filter context
   */
  filterOption: FilterContext;

  /**
   * Picks facets based on the compact filter option and sorts
   * them based on
   *
   * No specific type => Type name alphabetically => Bucket count
   */
  get facets(): FilterFacet[] {
    return this.filterOption.options.filter(it => it.buckets.length > 0);
  }

  /**
   * Possible languages to be used for translation
   */
  language: keyof SCTranslations<SCLanguage>;

  /**
   * Mapping of SCThingType
   */
  scThingType = SCThingType;

  /**
   * Container for the sort context
   */
  sortOption: SortContext;

  /**
   * Core translator
   */
  translator: SCThingTranslator;

  constructor(
    private translateService: TranslateService,
    private readonly contextMenuService: ContextMenuService,
  ) {
    this.language = this.translateService.currentLang as keyof SCTranslations<SCLanguage>;
    this.translator = new SCThingTranslator(this.language);

    this.translateService.onLangChange.pipe(takeUntilDestroyed()).subscribe((event: LangChangeEvent) => {
      this.language = event.lang as keyof SCTranslations<SCLanguage>;
      this.translator = new SCThingTranslator(this.language);
    });
    this.contextMenuService.filterContextChanged$.pipe(takeUntilDestroyed()).subscribe(filterContext => {
      this.filterOption = filterContext;
    });
    this.contextMenuService.sortOptions.pipe(takeUntilDestroyed()).subscribe(sortContext => {
      this.sortOption = sortContext;
    });
  }

  /**
   * Sets selected filter options and updates listener
   */
  filterChanged = () => {
    this.contextMenuService.contextFilterChanged(this.filterOption);
  };

  /**
   * Returns translated property value
   */
  getTranslatedPropertyValue(onlyForType: SCThingType, field: string, key?: string): string | undefined {
    return this.translator.translatedPropertyValue(onlyForType, field, key);
  }

  /**
   * Resets filter options
   */
  resetFilter = (option: FilterContext) => {
    for (const filterFacet of option.options)
      for (const filterBucket of filterFacet.buckets) {
        filterBucket.checked = false;
      }
    this.contextMenuService.contextFilterChanged(this.filterOption);
  };

  /**
   * Updates selected sort option and updates listener
   */
  sortChanged = (option: SortContext, value: SortContextOption) => {
    if (option.value === value.value) {
      if (value.reversible) {
        option.reversed = !option.reversed;
      }
    } else {
      option.value = value.value;
      if (value.reversible) {
        option.reversed = false;
      }
    }
    this.contextMenuService.contextSortChanged(option);
  };
}
