/*
 * Copyright (C) 2019-2022 Open 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 {SCLanguageCode, SCMetaTranslations, SCTranslations} from '../general/i18n.js';
import {SCThing, SCThingMeta, SCThingType} from './abstract/thing.js';
import {
  SCThingWithCategories,
  SCThingWithCategoriesSpecificValues,
  SCThingWithCategoriesTranslatableProperties,
  SCThingWithCategoriesWithoutReferences,
  SCThingWithCategoriesWithoutReferencesMeta,
} from './abstract/thing-with-categories.js';
import {SCUserGroup} from './abstract/user-groups.js';

/**
 * A setting without references
 */
export interface SCSettingWithoutReferences
  extends SCThingWithCategoriesWithoutReferences<SCSettingCategories, SCThingWithCategoriesSpecificValues> {
  /**
   * The default value of a setting
   */
  defaultValue: SCSettingValue | SCSettingValues;
  /**
   * The input type of this setting
   */
  inputType: SCSettingInputType;
  /**
   * The order number this setting should show up in its category list
   * @integer
   */
  order: number;
  /**
   * Translated fields of a setting
   */
  translations?: SCTranslations<SCSettingValueTranslatableProperties>;
  /**
   * The type of this model
   */
  type: SCThingType.Setting;
  /**
   * The key of a value of a setting
   */
  value?: SCSettingValue | SCSettingValues;
  /**
   * The possible values of a setting
   */
  values?: SCSettingValues;
}

/**
 * A list of categories for settings
 */
export type SCSettingCategories = 'profile' | 'privacy' | 'credentials' | 'others';

/**
 * The types of input/value a setting object can carry
 */
export enum SCSettingInputType {
  SingleChoice = 'single choice',
  MultipleChoice = 'multiple choice',
  Number = 'number',
  Text = 'text',
  Password = 'password',
}

/**
 * A setting with references
 * @validatable
 */
export interface SCSetting
  extends SCSettingWithoutReferences,
    SCThing,
    SCThingWithCategories<SCSettingCategories, SCThingWithCategoriesSpecificValues> {
  /**
   * Translated fields of a setting
   */
  translations?: SCTranslations<SCSettingValueTranslatableProperties>;
  /**
   * The type of this model
   */
  type: SCThingType.Setting;
}

/**
 * The type a value of a setting can have
 */
export type SCSettingValue = string | number | boolean;

/**
 * The type of multiple values a setting can have
 */
export type SCSettingValues = SCSettingValue[];

/**
 * Translatable properties of a setting
 */
export interface SCSettingValueTranslatableProperties extends SCThingWithCategoriesTranslatableProperties {
  /**
   * The translations of the possible values of a setting
   * @keyword
   */
  values?: string[];
}

/**
 * Meta information about settings
 */
export class SCSettingMeta extends SCThingMeta implements SCMetaTranslations<SCSetting> {
  /**
   * Translations of fields
   */
  fieldTranslations = {
    de: {
      ...new SCThingWithCategoriesWithoutReferencesMeta<
        SCSettingCategories,
        SCThingWithCategoriesSpecificValues
      >().fieldTranslations.de,
      defaultValue: 'Standard Wert',
      inputType: 'Eingabetyp',
      order: 'Position',
      value: 'Wert',
      values: 'Werte',
    },
    en: {
      ...new SCThingWithCategoriesWithoutReferencesMeta<
        SCSettingCategories,
        SCThingWithCategoriesSpecificValues
      >().fieldTranslations.en,
      defaultValue: 'default value',
      inputType: 'input type',
      order: 'position',
      value: 'value',
      values: 'values',
    },
  };

  /**
   * Translations of values of fields
   */
  fieldValueTranslations = {
    de: {
      ...new SCThingWithCategoriesWithoutReferencesMeta<
        SCSettingCategories,
        SCThingWithCategoriesSpecificValues
      >().fieldValueTranslations.de,
      categories: {
        credentials: 'Anmeldedaten',
        others: 'Andere',
        privacy: 'Privatsphäre',
        profile: 'Profil',
      },
      inputType: {
        'multiple choice': 'mehrfach Auswahl',
        'number': 'Zahl',
        'password': 'Passwort',
        'single choice': 'einfache Auswahl',
        'text': 'Text',
      },
      type: 'Einstellung',
    },
    en: {
      ...new SCThingWithCategoriesWithoutReferencesMeta<
        SCSettingCategories,
        SCThingWithCategoriesSpecificValues
      >().fieldValueTranslations.en,
      type: SCThingType.Setting,
    },
  };
}

/**
 * A user group setting
 */
export interface SCUserGroupSetting extends SCSetting {
  /**
   * Exact categories of the setting
   */
  categories: ['profile'];
  /**
   * The default value of the setting
   */
  defaultValue: SCUserGroup;
  /**
   * Specific name of the setting
   */
  name: 'group';
  /**
   * Chosen value of the setting
   */
  value?: SCUserGroup;
  /**
   * The possible values of the setting
   */
  values: SCUserGroup[];
}

/**
 * A language setting
 */
export interface SCLanguageSetting extends SCSetting {
  /**
   * Exact categories of the setting
   */
  categories: ['profile'];
  /**
   * The default value of the setting
   */
  defaultValue: SCLanguageCode;
  /**
   * Specific name of the setting
   */
  name: 'language';
  /**
   * Chosen value of the setting
   */
  value?: SCLanguageCode;
  /**
   * The possible values of the setting
   */
  values: SCLanguageCode[];
}
