/**
 * @license
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
import '../../shared/gr-select/gr-select';
import '../../shared/gr-textarea/gr-textarea';
import {
  AutocompleteSuggestion,
  AutocompleteQuery,
} from '../../shared/gr-autocomplete/gr-autocomplete';
import {GroupId, GroupInfo, GroupName} from '../../../types/common';
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {getAppContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
import {convertToString} from '../../../utils/string-util';
import {BindValueChangeEvent} from '../../../types/events';
import {fontStyles} from '../../../styles/gr-font-styles';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
import {subpageStyles} from '../../../styles/gr-subpage-styles';
import {LitElement, PropertyValues, css, html} from 'lit';
import {customElement, property, state} from 'lit/decorators';

const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;

const OPTIONS = {
  submitFalse: {
    value: false,
    label: 'False',
  },
  submitTrue: {
    value: true,
    label: 'True',
  },
};

export interface GroupNameChangedDetail {
  name: GroupName;
  external: boolean;
}

declare global {
  interface HTMLElementTagNameMap {
    'gr-group': GrGroup;
  }
}

@customElement('gr-group')
export class GrGroup extends LitElement {
  /**
   * Fired when the group name changes.
   *
   * @event name-changed
   */

  private readonly query: AutocompleteQuery;

  @property({type: String})
  groupId?: GroupId;

  @state() private originalOwnerName?: string;

  @state() private originalDescriptionName?: string;

  @state() private originalOptionsVisibleToAll?: boolean;

  @state() private submitTypes = Object.values(OPTIONS);

  // private but used in test
  @state() isAdmin = false;

  // private but used in test
  @state() groupOwner = false;

  // private but used in test
  @state() groupIsInternal = false;

  // private but used in test
  @state() loading = true;

  // private but used in test
  @state() groupConfig?: GroupInfo;

  // private but used in test
  @state() groupConfigOwner?: string;

  // private but used in test
  @state() originalName?: GroupName;

  private readonly restApiService = getAppContext().restApiService;

  constructor() {
    super();
    this.query = (input: string) => this.getGroupSuggestions(input);
  }

  override connectedCallback() {
    super.connectedCallback();
  }

  static override get styles() {
    return [
      fontStyles,
      formStyles,
      sharedStyles,
      subpageStyles,
      css`
        h3.edited:after {
          color: var(--deemphasized-text-color);
          content: ' *';
        }
      `,
    ];
  }

  override render() {
    return html`
      <div class="main gr-form-styles read-only">
        <div id="loading" class=${this.computeLoadingClass()}>Loading...</div>
        <div id="loadedContent" class=${this.computeLoadingClass()}>
          <h1 id="Title" class="heading-1">${this.originalName}</h1>
          <h2 id="configurations" class="heading-2">General</h2>
          <div id="form">
            <fieldset>
              ${this.renderGroupUUID()} ${this.renderGroupName()}
              ${this.renderGroupOwner()} ${this.renderGroupDescription()}
              ${this.renderGroupOptions()}
            </fieldset>
          </div>
        </div>
      </div>
    `;
  }

  private renderGroupUUID() {
    return html`
      <h3 id="groupUUID" class="heading-3">Group UUID</h3>
      <fieldset>
        <gr-copy-clipboard
          id="uuid"
          .text=${this.getGroupUUID()}
        ></gr-copy-clipboard>
      </fieldset>
    `;
  }

  private renderGroupName() {
    const groupNameEdited = this.originalName !== this.groupConfig?.name;
    return html`
      <h3
        id="groupName"
        class="heading-3 ${this.computeHeaderClass(groupNameEdited)}"
      >
        Group Name
      </h3>
      <fieldset>
        <span class="value">
          <gr-autocomplete
            id="groupNameInput"
            .text=${this.groupConfig?.name}
            ?disabled=${this.computeGroupDisabled()}
            @text-changed=${this.handleNameTextChanged}
          ></gr-autocomplete>
        </span>
        <span class="value">
          <gr-button
            id="inputUpdateNameBtn"
            ?disabled=${!groupNameEdited}
            @click=${this.handleSaveName}
          >
            Rename Group</gr-button
          >
        </span>
      </fieldset>
    `;
  }

  private renderGroupOwner() {
    const groupOwnerNameEdited =
      this.originalOwnerName !== this.groupConfig?.owner;
    return html`
      <h3
        id="groupOwner"
        class="heading-3 ${this.computeHeaderClass(groupOwnerNameEdited)}"
      >
        Owners
      </h3>
      <fieldset>
        <span class="value">
          <gr-autocomplete
            id="groupOwnerInput"
            .text=${this.groupConfig?.owner}
            .value=${this.groupConfigOwner}
            .query=${this.query}
            ?disabled=${this.computeGroupDisabled()}
            @text-changed=${this.handleOwnerTextChanged}
            @value-changed=${this.handleOwnerValueChanged}
          >
          </gr-autocomplete>
        </span>
        <span class="value">
          <gr-button
            id="inputUpdateOwnerBtn"
            ?disabled=${!groupOwnerNameEdited}
            @click=${this.handleSaveOwner}
          >
            Change Owners</gr-button
          >
        </span>
      </fieldset>
    `;
  }

  private renderGroupDescription() {
    const groupDescriptionEdited =
      this.originalDescriptionName !== this.groupConfig?.description;
    return html`
      <h3 class="heading-3 ${this.computeHeaderClass(groupDescriptionEdited)}">
        Description
      </h3>
      <fieldset>
        <div>
          <gr-textarea
            class="description"
            autocomplete="on"
            rows="4"
            monospace
            ?disabled=${this.computeGroupDisabled()}
            .text=${this.groupConfig?.description}
            @text-changed=${this.handleDescriptionTextChanged}
          ></gr-textarea>
        </div>
        <span class="value">
          <gr-button
            ?disabled=${!groupDescriptionEdited}
            @click=${this.handleSaveDescription}
          >
            Save Description
          </gr-button>
        </span>
      </fieldset>
    `;
  }

  private renderGroupOptions() {
    // We make sure the value is a boolean
    // this is done so undefined is converted to false.
    const groupOptionsEdited =
      Boolean(this.originalOptionsVisibleToAll) !==
      Boolean(this.groupConfig?.options?.visible_to_all);

    // We have to convert boolean to string in order
    // for the selection to work correctly.
    // We also convert undefined to false using boolean.
    return html`
      <h3
        id="options"
        class="heading-3 ${this.computeHeaderClass(groupOptionsEdited)}"
      >
        Group Options
      </h3>
      <fieldset>
        <section>
          <span class="title">
            Make group visible to all registered users
          </span>
          <span class="value">
            <gr-select
              id="visibleToAll"
              .bindValue=${convertToString(
                Boolean(this.groupConfig?.options?.visible_to_all)
              )}
              @bind-value-changed=${this.handleOptionsBindValueChanged}
            >
              <select ?disabled=${this.computeGroupDisabled()}>
                ${this.submitTypes.map(
                  item => html`
                    <option value=${item.value}>${item.label}</option>
                  `
                )}
              </select>
            </gr-select>
          </span>
        </section>
        <span class="value">
          <gr-button
            ?disabled=${!groupOptionsEdited}
            @click=${this.handleSaveOptions}
          >
            Save Group Options
          </gr-button>
        </span>
      </fieldset>
    `;
  }

  override willUpdate(changedProperties: PropertyValues) {
    if (changedProperties.has('groupId')) {
      this.loadGroup();
    }
  }

  // private but used in test
  async loadGroup() {
    if (!this.groupId) return;

    const promises: Promise<unknown>[] = [];

    const errFn: ErrorCallback = response => {
      firePageError(response);
    };

    const config = await this.restApiService.getGroupConfig(
      this.groupId,
      errFn
    );
    if (!config || !config.name) return;

    if (config.description === undefined) {
      config.description = '';
    }

    this.originalName = config.name;
    this.originalOwnerName = config.owner;
    this.originalDescriptionName = config.description;
    this.groupIsInternal = !!config.id.match(INTERNAL_GROUP_REGEX);

    promises.push(
      this.restApiService.getIsAdmin().then(isAdmin => {
        this.isAdmin = !!isAdmin;
      })
    );

    promises.push(
      this.restApiService.getIsGroupOwner(config.name).then(isOwner => {
        this.groupOwner = !!isOwner;
      })
    );

    this.groupConfig = config;
    this.originalOptionsVisibleToAll = config?.options?.visible_to_all;

    fireTitleChange(this, config.name);

    await Promise.all(promises);
    this.loading = false;
  }

  // private but used in test
  computeLoadingClass() {
    return this.loading ? 'loading' : '';
  }

  // private but used in test
  async handleSaveName() {
    const groupConfig = this.groupConfig;
    if (!this.groupId || !groupConfig || !groupConfig.name) {
      return Promise.reject(new Error('invalid groupId or config name'));
    }
    const groupName = groupConfig.name;
    const config = await this.restApiService.saveGroupName(
      this.groupId,
      groupName
    );
    if (config.status === 200) {
      this.originalName = groupName;
      const detail: GroupNameChangedDetail = {
        name: groupName,
        external: !this.groupIsInternal,
      };
      this.dispatchEvent(
        new CustomEvent('name-changed', {
          detail,
          composed: true,
          bubbles: true,
        })
      );
      this.requestUpdate();
    }

    return;
  }

  // private but used in test
  async handleSaveOwner() {
    if (!this.groupId || !this.groupConfig) return;
    let owner = this.groupConfig.owner;
    if (this.groupConfigOwner) {
      owner = decodeURIComponent(this.groupConfigOwner);
    }
    if (!owner) return;
    await this.restApiService.saveGroupOwner(this.groupId, owner);
    this.originalOwnerName = this.groupConfig?.owner;
    this.groupConfigOwner = undefined;
  }

  // private but used in test
  async handleSaveDescription() {
    if (
      !this.groupId ||
      !this.groupConfig ||
      this.groupConfig.description === undefined
    )
      return;
    await this.restApiService.saveGroupDescription(
      this.groupId,
      this.groupConfig.description
    );
    this.originalDescriptionName = this.groupConfig.description;
  }

  // private but used in test
  async handleSaveOptions() {
    if (!this.groupId || !this.groupConfig || !this.groupConfig.options) return;
    const visible = this.groupConfig.options.visible_to_all;
    const options = {visible_to_all: visible};
    await this.restApiService.saveGroupOptions(this.groupId, options);
    this.originalOptionsVisibleToAll = visible;
  }

  private computeHeaderClass(configChanged: boolean) {
    return configChanged ? 'edited' : '';
  }

  private getGroupSuggestions(input: string) {
    return this.restApiService.getSuggestedGroups(input).then(response => {
      const groups: AutocompleteSuggestion[] = [];
      for (const [name, group] of Object.entries(response ?? {})) {
        groups.push({name, value: decodeURIComponent(group.id)});
      }
      return groups;
    });
  }

  // private but used in test
  computeGroupDisabled() {
    return !(this.groupIsInternal && (this.isAdmin || this.groupOwner));
  }

  private getGroupUUID() {
    const id = this.groupConfig?.id;
    if (!id) return;
    return id.match(INTERNAL_GROUP_REGEX) ? id : decodeURIComponent(id);
  }

  private handleNameTextChanged(e: CustomEvent) {
    if (!this.groupConfig || this.loading) return;
    this.groupConfig.name = e.detail.value as GroupName;
    this.requestUpdate();
  }

  private handleOwnerTextChanged(e: CustomEvent) {
    if (!this.groupConfig || this.loading) return;
    this.groupConfig.owner = e.detail.value;
    this.requestUpdate();
  }

  private handleOwnerValueChanged(e: CustomEvent) {
    if (this.loading) return;
    this.groupConfigOwner = e.detail.value;
    this.requestUpdate();
  }

  private handleDescriptionTextChanged(e: CustomEvent) {
    if (!this.groupConfig || this.loading) return;
    this.groupConfig.description = e.detail.value;
    this.requestUpdate();
  }

  private handleOptionsBindValueChanged(e: BindValueChangeEvent) {
    if (!this.groupConfig || this.loading) return;

    // Because the value for e.detail.value is a string
    // we convert the value to a boolean.
    const value = e.detail.value === 'true' ? true : false;
    this.groupConfig.options!.visible_to_all = value;
    this.requestUpdate();
  }
}
