import { html, TemplateResult, CSSResult } from 'lit';
import { ApplicationInit, ApplicationScreen } from '../ApplicationScreen.js';
import { reactive } from '../../lib/decorators.js';
import styles from './Authenticate.styles.js';
import globalStyles from '../../styles/global-styles.js';
import typography from '../../styles/m3/typography.module.js';
import colors from '../../styles/m3/colors.module.js';
import dialog from '../../styles/m3/dialog.module.js';
import { IConfigEnvironment } from '../../lib/config/Config.js';
import { ISessionInitInfo } from '../../store/HttpStore.js';
import { EnvironmentsKey } from '../../bindings/base/ConfigurationBindings.js';
import '../../define/ui/ui-progress.js';
import '../../define/ui/ui-button.js';

/**
 * When the user is redirected here it means that the user provided a configuration
 * that requires user authentication.
 */
export default class AuthenticateScreen extends ApplicationScreen {
  override async storeChanged(): Promise<void> {
    // ...
  }

  static get styles(): CSSResult[] {
    return [styles, globalStyles, typography, colors, dialog];
  }

  @reactive() environmentError?: string;

  environment?: IConfigEnvironment;

  /**
   * Whether the application is performing the store validation.
   */
  @reactive() authenticating = false;

  isSessionStore = false;

  constructor(init: ApplicationInit) {
    super(init);
  }

  async initialize(): Promise<void> {
    try {
      await this.bindings.store.initialize();
      await this.bindings.store.initializeStore();
      await this.bindings.config.initialize();
      const env = await this.readEnvironment();
      if (env) {
        this.environment = env;
      } else {
        this.environmentError = 'Environment information not found. Go back to the previous page.';
      }
    } catch (e) {
      this.environmentError = (e as Error).message;
    }
  }

  async readEnvironment(): Promise<IConfigEnvironment | undefined> {
    let env = await this.bindings.config.session.get(`${EnvironmentsKey}.creating`) as IConfigEnvironment | undefined;
    if (!env) {
      env = await this.bindings.config.environment.read();
    } else {
      this.isSessionStore = true;
    }
    return env;
  }

  protected async handleAuth(): Promise<void> {
    const { environment } = this;
    if (!environment) {
      this.environmentError = 'Environment information not found. Go back to the previous page.';
      return;
    }
    this.authenticate(environment);
  }

  protected handleBack(): void {
    window.history.back();
  }

  protected async authenticate(env: IConfigEnvironment): Promise<void> {
    this.authenticating = true;
    let info: ISessionInitInfo | undefined;
    try {
      await this.bindings.store.global.set(env);
      info = await this.bindings.store.auth.authenticate({ force: false });
    } finally {
      this.authenticating = false;
    }
    if (info) {
      if (this.isSessionStore) {
        await this.bindings.config.environment.add(env, { asDefault: true });
        await this.bindings.config.session.delete(`${EnvironmentsKey}.creating`);
      } else {
        await this.bindings.config.environment.update(env);
      }
    }
  }

  /**
   * This to be used by the child classes to render page template.
   * @returns Application page template
   */
  override pageTemplate(): TemplateResult {
    return html`
    <main class="config-init">
      ${this.renderTitle()}
      ${this.renderIntroMessage()}
      ${this.environmentError ? this.initErrorTemplate() : this.contentTemplate()}
    </main>
    `;
  }

  initErrorTemplate(): TemplateResult {
    return html`
    <p class="general-error error on-error-text body-large">${this.environmentError}</p>
    <div class="action">
      <ui-button type="filled" @click="${this.handleBack}">Back</ui-button>
    </div>
    `;
  }

  contentTemplate(): TemplateResult {
    return html`
    ${this.actionTemplate()}
    ${this.infoTemplate()}
    ${this.progressTemplate()}
    `;
  }

  renderTitle(): TemplateResult {
    return html`<h1 class="display-large">Store authentication</h1>`;
  }

  renderIntroMessage(): TemplateResult {
    return html`
    <div class="description body-medium">
      <p id="authenticationMessage">The network store requires authentication.</p>
    </div>
    `;
  }

  actionTemplate(): TemplateResult {
    return html`
    <div class="action">
      <ui-button 
        type="filled"
        @click="${this.handleAuth}"
      >Authenticate</ui-button>
    </div>
    `;
  }

  infoTemplate(): TemplateResult {
    return html`
    <p class="description body-medium" id="authenticationMessage">This will open a new tab with the authentication options.</p>
    `;
  }

  progressTemplate(): TemplateResult | string {
    const { authenticating } = this;
    if (!authenticating) {
      return '';
    }
    return html`
    <ui-progress indeterminate></ui-progress>
    `;
  }
}
