import { __decorate } from "tslib";
import { html, nothing } from 'lit';
import { Events as CoreEvents } from '@api-client/core/build/browser.js';
import { reactive } from '../../lib/decorators.js';
import { navigate } from '../../lib/route.js';
import globalStyles from '../../styles/global-styles.js';
import styles from './StoreConfig.styles.js';
import typography from '../../styles/m3/typography.module.js';
import colorStyles from '../../styles/m3/colors.module.js';
import dialogStyles from '../../styles/m3/dialog.module.js';
import surfaceStyles from '../../styles/m3/surface.module.js';
import { ApplicationScreen } from '../ApplicationScreen.js';
import '@github/relative-time-element';
import '../../define/dialog/rename-dialog.js';
import '../../define/dialog/confirm-delete-dialog.js';
import '../../define/ui/ui-icon.js';
import '../../define/ui/ui-button.js';
import '../../define/ui/ui-dropdown-list.js';
import '../../define/ui/ui-list.js';
import '../../define/ui/ui-list-item.js';
import '../../define/ui/ui-progress.js';
import '../../define/ui/ui-dialog.js';
import '../../define/ui/ui-radio.js';
import '../../define/ui/ui-text-field.js';
import '../../define/app-navigation-item.js';
export default class StoreConfigScreen extends ApplicationScreen {
    async storeChanged() {
        // ...
    }
    static get styles() {
        return [globalStyles, typography, colorStyles, dialogStyles, styles, surfaceStyles];
    }
    static get routes() {
        return [
            { pattern: '/start', method: 'startRoute', fallback: true, name: 'Store welcome', title: 'Store Configuration Welcome' },
            { pattern: '/store/(?<key>.*)', method: 'storeRoute', name: 'Store configuration', title: 'Store configuration' },
            { pattern: '/new', method: 'newRoute', name: 'New store configuration', title: 'New store configuration' },
            { pattern: '*', method: 'telemetryRoute' },
        ];
    }
    /**
     * The list of environments to render.
     */
    get environments() {
        const { config } = this;
        const envs = config?.environments;
        if (!envs) {
            return [];
        }
        return envs;
    }
    get firstRun() {
        return this.firstRunInternal;
    }
    set firstRun(value) {
        if (this.firstRunInternal === value) {
            return;
        }
        this.firstRunInternal = value;
        if (value) {
            document.body.classList.add('first-run');
        }
        else {
            document.body.classList.remove('first-run');
        }
        this.render();
    }
    constructor(init) {
        super(init);
        /**
         * Whether the current environment is a default environment
         */
        this.isDefault = false;
        /**
         * Flag set when the screen is requesting the list of environments.
         */
        this.loadingEnvironments = false;
        /**
         * Whether the dialog with the help message is opened.
         */
        this.infoDialogOpened = false;
        /**
         * Whether the application is performing the store validation.
         */
        this.validating = false;
        /**
         * Init reason to pass with the create event.
         */
        this.initReason = 'add';
        this.firstRunInternal = false;
    }
    async initialize() {
        if (!await this.isPlatformSupported()) {
            return;
        }
        await this.bindings.store.initialize();
        await this.bindings.store.initializeStore();
        await this.bindings.config.initialize();
        await this.initializeConfig();
        try {
            await this.initializeStore(false);
        }
        catch (e) {
            // ...
        }
        await this.listEnvironments();
        this.setupFirstRun();
        const url = new URL(window.location.href);
        if (url.searchParams.has('init-reason')) {
            this.initReason = url.searchParams.get('init-reason');
        }
        else {
            this.initReason = 'add';
        }
        this.initializeRouting();
        this.initialized = true;
    }
    setupFirstRun() {
        const { environments } = this;
        this.firstRun = environments.length === 0;
    }
    async listEnvironments() {
        this.loadingEnvironments = true;
        this.config = undefined;
        try {
            this.config = await this.bindings.config.environment.list();
        }
        catch (e) {
            const err = e;
            CoreEvents.Telemetry.exception(err.message, true);
            this.reportCriticalError('Unable to load the list of environments.');
        }
        finally {
            this.loadingEnvironments = false;
        }
    }
    resetRoute() {
        this.page = undefined;
        this.selected = undefined;
        this.env = undefined;
        this.isDefault = false;
    }
    startRoute() {
        this.resetRoute();
        this.page = 'start';
    }
    storeRoute(info) {
        if (!info.params || !info.params.key) {
            throw new Error(`Invalid route configuration. Missing parameters.`);
        }
        this.resetRoute();
        const key = info.params.key;
        this.page = 'store';
        this.selected = key;
        const { config } = this;
        if (config && config.environments) {
            const env = config.environments.find(i => i.key === key);
            this.env = env;
            this.isDefault = !!env && env.key === config.current;
        }
    }
    newRoute() {
        this.resetRoute();
        this.page = 'new';
    }
    telemetryRoute(info) {
        CoreEvents.Telemetry.view(info.route.name || info.route.pattern || '/');
    }
    handleSourceSelected(e) {
        const radio = e.target;
        this.storeType = radio.value;
    }
    handleOpenHelp(e) {
        e.preventDefault();
        this.infoDialogOpened = true;
    }
    handleDialogClose() {
        this.infoDialogOpened = false;
    }
    handleContinue() {
        const info = this.createInit();
        if (!info) {
            return;
        }
        this.validateInput(info);
    }
    handleCancel() {
        window.history.back();
    }
    createInit() {
        if (!this.storeType) {
            return undefined;
        }
        const isNetwork = this.storeType === 'network-store';
        let location;
        if (isNetwork) {
            const input = document.querySelector('.store-url');
            if (!input.checkValidity()) {
                return undefined;
            }
            location = input.value.trim();
            if (!location) {
                return undefined;
            }
            if (location.endsWith('/')) {
                location = location.substring(0, location.length - 1);
            }
        }
        const info = {
            source: this.storeType,
            location,
            reason: this.initReason,
        };
        return info;
    }
    async validateInput(init) {
        if (init.source === 'network-store') {
            this.validating = true;
            const error = await this.validateNetworkStore(init.location);
            this.validating = false;
            if (error) {
                this.validationError = error;
                return;
            }
        }
        await this.storeEnvironment(init);
    }
    async storeEnvironment(init) {
        const { config } = this;
        const envs = config?.environments;
        const hasEnvironments = !!envs && !!envs.length;
        if (!hasEnvironments) {
            // eslint-disable-next-line no-param-reassign
            init.asDefault = true;
        }
        await this.bindings.store.environment.init(init);
    }
    async validateNetworkStore(baseUri) {
        try {
            const info = await this.bindings.store.environment.readStoreInfo(baseUri);
            if (!info) {
                throw new Error(`Unable to connect.`);
            }
        }
        catch (e) {
            return e.message;
        }
        return undefined;
    }
    handleConfigBroadcast(e) {
        const event = e.data;
        const { path } = event;
        if (path === 'environment.setDefault') {
            this.handleDefaultEnvironmentSet(event.env);
        }
        else if (path === 'environment.add') {
            this.handleEnvironmentAdd(event.env, event.init);
        }
        else if (path === 'environment.remove') {
            this.handleEnvironmentRemoved(event.id);
        }
        else if (path === 'environment.update') {
            this.handleEnvironmentUpdated(event.env);
        }
    }
    handleEnvironmentUpdated(env) {
        const { config } = this;
        if (!env || !config) {
            return;
        }
        if (!config.environments) {
            config.environments = [];
        }
        const index = config.environments.findIndex(i => i.key === env.key);
        if (index >= 0) {
            config.environments[index] = env;
        }
        else {
            config.environments.push(env);
        }
        if (this.env && this.env.key === env.key) {
            this.env = env;
        }
        this.render();
    }
    handleEnvironmentRemoved(id) {
        const { config } = this;
        if (!id || !config) {
            return;
        }
        if (!config.environments) {
            return;
        }
        const index = config.environments.findIndex(i => i.key === id);
        if (index >= 0) {
            config.environments.splice(index, 1);
            this.render();
        }
        if (this.selected === id) {
            navigate('start');
        }
        this.setupFirstRun();
    }
    handleDefaultEnvironmentSet(env) {
        const { config } = this;
        if (!env || !config) {
            return;
        }
        this.revalidateCurrent(env.key);
    }
    handleEnvironmentAdd(env, init = {}) {
        const { config } = this;
        if (!config) {
            return;
        }
        if (!config.environments) {
            config.environments = [];
        }
        config.environments.push(env);
        if (init.asDefault) {
            this.revalidateCurrent(env.key);
        }
        if (['new', 'start'].includes(this.page)) {
            navigate('store', env.key);
        }
        else {
            this.render();
        }
        this.setupFirstRun();
    }
    revalidateCurrent(id) {
        const { config } = this;
        if (!config) {
            throw new Error(`Config is not set.`);
        }
        config.current = id;
        if (this.env) {
            this.isDefault = this.env.key === id;
        }
    }
    handleOption(e) {
        const element = e.detail.item;
        const { option } = element.dataset;
        if (!option) {
            return;
        }
        switch (option) {
            case 'rename':
                this.renameEnvironment();
                break;
            case 'make-default':
                this.makeEnvironmentDefault();
                break;
            case 'delete':
                this.deleteEnvironment();
                break;
            case 'authenticate':
                this.authenticateEnvironment();
                break;
            default:
        }
    }
    renameEnvironment() {
        const { env } = this;
        if (!env) {
            throw new Error(`Environment not set`);
        }
        const dialog = document.createElement('rename-dialog');
        dialog.name = env.name;
        dialog.modal = true;
        dialog.open = true;
        document.body.appendChild(dialog);
        dialog.addEventListener('close', (ev) => {
            document.body.removeChild(dialog);
            const event = ev;
            const { cancelled, value } = event.detail;
            if (!cancelled && value) {
                this.bindings.config.environment.update({ ...env, name: value });
            }
        });
    }
    deleteEnvironment() {
        const { env } = this;
        if (!env) {
            throw new Error(`Environment not set`);
        }
        const dialog = document.createElement('confirm-delete-dialog');
        dialog.open = true;
        dialog.modal = true;
        const message = document.createElement('span');
        message.textContent = 'Are you sure you want to delete this store configuration?';
        dialog.appendChild(message);
        document.body.appendChild(dialog);
        dialog.addEventListener('close', (ev) => {
            document.body.removeChild(dialog);
            const event = ev;
            const { cancelled } = event.detail;
            if (!cancelled) {
                this.bindings.config.environment.remove(env.key);
            }
        });
    }
    async makeEnvironmentDefault() {
        const { selected } = this;
        if (!selected) {
            return;
        }
        await this.bindings.config.environment.setDefault(selected);
    }
    async authenticateEnvironment() {
        const { env } = this;
        if (!env) {
            return;
        }
        await this.bindings.store.auth.authenticate({
            force: true,
            updateEnvironment: true,
            env,
        });
    }
    handleAddNewEnvironment() {
        navigate('new');
    }
    storeNavHandler(e) {
        const target = e.target;
        const { key } = target.dataset;
        if (!key) {
            return;
        }
        navigate('store', key);
    }
    pageTemplate() {
        const { initialized } = this;
        if (!initialized) {
            return super.pageTemplate();
        }
        if (this.firstRun) {
            return this.renderFirstRun();
        }
        return html `
      ${this.headerTemplate()}
      ${this.navigationTemplate()}
      ${this.mainTemplate()}
      ${this.renderHelpDialog()}
    `;
    }
    renderFirstRun() {
        return html `
    ${this.renderFirstRunHeader()}
    <main class="surface1">
      ${this.addNewTemplate()}
    </main>
    ${this.renderHelpDialog()}
    `;
    }
    renderFirstRunHeader() {
        return html `
    <header class="start-page-header">
      <h1 class="headline-medium first-run">Welcome to API Client</h1>
    </header>
    `;
    }
    headerTemplate() {
        return html `
    <header class="start-page-header">
      <h1 class="title-large">Store configuration</h1>
    </header>
    `;
    }
    navigationTemplate() {
        const { config } = this;
        const envs = config?.environments;
        const hasEnvironments = !!envs && !!envs.length;
        return html `
    <nav aria-label="existing stores">
      <ui-button title="Opens a form to create a new environment" @click="${this.handleAddNewEnvironment}">
        <ui-icon icon="add" slot="icon"></ui-icon>
        Add new
      </ui-button>
      ${hasEnvironments ? this.navigationConfigTemplate(envs) : nothing}
    </nav>
    `;
    }
    navigationConfigTemplate(envs) {
        return html `
    <ol class="nav-list">
      ${envs.map(i => this.navigationItemTemplate(i))}
    </ol>
    `;
    }
    navigationItemTemplate(item) {
        const { selected, config } = this;
        const isDefault = !!config && item.key === config.current;
        const name = item.name || 'Unnamed configuration';
        // const needsAuth = item.source === 'network-store' && !item.authenticated;
        return html `
      <li>
        <app-navigation-item data-key="${item.key}" .selected=${selected === item.key} @click="${this.storeNavHandler}">
          ${isDefault ? html `<ui-icon icon="taskAlt" slot="icon" title="Default configuration">` : ''}
          ${name}
        </app-navigation-item>
      </li>
    `;
    }
    renderAddButton() {
        return html `<ui-button 
      type="tonal"
      class="add-button" 
      title="Opens a form to create a new environment"
      @click="${this.handleAddNewEnvironment}"
    >Add new</ui-button>`;
    }
    mainTemplate() {
        let template;
        switch (this.page) {
            case 'store':
                template = this.storeTemplate();
                break;
            case 'new':
                template = this.addNewTemplate();
                break;
            default:
                template = this.startTemplate();
                break;
        }
        return html `
    <main class="surface1">
      ${this.renderProgress()}
      ${template}
    </main>
    `;
    }
    startTemplate() {
        const { config } = this;
        if (!config || !config.environments || !config.environments.length) {
            return html `
      <p class="body-large">It looks like you have no stores configured.</p>
      `;
        }
        return html `
    <p class="body-large">Store configuration allows you to manage connections to different API stores.</p>
    `;
    }
    storeTemplate() {
        const { config, env } = this;
        if (!config || !env) {
            return html `Invalid state, config not ready.`;
        }
        const isDefault = env.key === config.current;
        const isLocal = env.source === 'local-store';
        return html `
    <section>
      <div class="title-area">
        <h2 class="title-medium text-selectable">${env.name || 'Unnamed configuration'}</h2>
        ${this.environmentOptionsTemplate()}
      </div>
      <dl class="body-medium">
        <dt>Key:</dt>
        <dd class="text-selectable">${env.key}</dd>

        <dt>URI</dt>
        <dd class="text-selectable">${env.location}</dd>

        <dt>Source</dt>
        <dd class="text-selectable">${isLocal ? 'Local store' : 'Network store'}</dd>

        <dt>Default environment</dt>
        <dd>${isDefault ? 'Yes' : 'No'}</dd>

        ${isLocal ? '' : this.storeSessionInfo(env)}
    </dl>
    </section>
    `;
    }
    storeSessionInfo(env) {
        const { tokenExpires } = env;
        const time = tokenExpires ? new Date(tokenExpires) : undefined;
        return html `
    <dt>Authenticated</dt>
    <dd>${env.authenticated ? 'Yes' : 'No'}</dd>

    <dt>Token expires</dt>
    <dd>${time ? html `<relative-time datetime="${time.toISOString()}"></relative-time>` : 'Unknown'}</dd>
    `;
    }
    environmentOptionsTemplate() {
        return html `
    <ui-dropdown-list
      verticalAlign="top"
      @select="${this.handleOption}"
      class="environment-dropdown"
      closeOnOutsideClick
    >
      <ui-icon-button aria-label="Press to select available options"><ui-icon icon="moreVert" role="presentation"></ui-icon></ui-icon-button>
      <ui-list slot="dropdown" role="menu">
        <ui-list-item role="menuitem" data-option="rename" image="icon" title="Renames this environment">
          <ui-icon role="presentation" slot="start" icon="rename"></ui-icon>
          Rename
        </ui-list-item>
        <ui-list-item role="menuitem" data-option="make-default" image="icon" title="Marks this environment as default" ?disabled="${this.isDefault}">
          <ui-icon role="presentation" slot="start" icon="checkBox"></ui-icon>
          Make default
        </ui-list-item>
        <ui-list-item role="menuitem" data-option="authenticate" image="icon" title="Authenticate the environment">
          <ui-icon role="presentation" slot="start" icon="key"></ui-icon>
          Authenticate
        </ui-list-item>
        <ui-list-item role="menuitem" data-option="delete" image="icon" title="Deletes the environment">
          <ui-icon role="presentation" slot="start" icon="deleteOutline"></ui-icon>
          Delete
        </ui-list-item>
      </ui-list>
    </ui-dropdown-list>
    `;
    }
    addNewTemplate() {
        return html `
    <h2 class="title-medium">Configure data store</h2>
    <form class="form">
      ${this.renderIntro()}
      ${this.renderStoreType()}
      ${this.renderStoreUrlInput()}
      ${this.renderProgress()}
      ${this.renderValidationError()}
    </form>
    ${this.renderActions()}
    `;
    }
    renderIntro() {
        return html `
    <div class="body-medium">
      <p>
        Select the type of the store the application will use. For a single user we recommend the <i>Local store</i> option.
      </p>
      <a href="#" @click="${this.handleOpenHelp}">Help me decide.</a>
    </div>
    `;
    }
    renderStoreType() {
        return html `
    <div class="data-source">
      <div>
        <label class="label-medium">
          <ui-radio name="source" value="local-store" .checked="${this.storeType === 'local-store'}" @change="${this.handleSourceSelected}"></ui-radio>
          Local store
        </label>
      </div>
      <div>
        <label class="label-medium">
          <ui-radio name="source" value="network-store" .checked="${this.storeType === 'network-store'}" @change="${this.handleSourceSelected}"></ui-radio>
          Network store
        </label>
      </div>
    </div>
    `;
    }
    renderStoreUrlInput() {
        if (this.storeType !== 'network-store') {
            return '';
        }
        return html `
    <div class="store-url-input">
      <ui-text-field
        class="store-url"
        type="url"
        name="location"
        required
        invalidText="The entered URL is invalid. Please, enter the address of the data store."
        supportingText="Enter the address to the store"
        label="Store address"
      ></ui-text-field>
    </div>
    `;
    }
    renderActions() {
        const canCancel = this.initReason !== 'first-run';
        return html `
    <div class="actions">
      ${canCancel ? html `<ui-button
        type="text"
        @click="${this.handleCancel}"
      >Cancel</ui-button>` : nothing}
      <ui-button 
        type="filled"
        ?disabled="${!this.storeType}" 
        @click="${this.handleContinue}"
      >Continue</ui-button>
    </div>
    `;
    }
    renderHelpDialog() {
        return html `
    <ui-dialog 
      ?open="${this.infoDialogOpened}" 
      @close="${this.handleDialogClose}" 
      class="help-dialog"
      modal
    >
      <ui-icon slot="icon" icon="help"></ui-icon>
      
      <span slot="title">Selecting Data Source</span>
      
      <section>
        <div class="label-large">Local Store</div>
        <p class="body-large">
          This will install a service on your machine that serves data to the API Client suite. 
          You can access your data only on this device.
        </p>
        <div class="label-large">Network Store</div>
        <p class="body-large">
          Allows you to connect to a store that is in your local network or over internet. 
          You will need the store address to continue.
        </p>
      </section>

      <ui-button slot="button" value="confirm" type="text">close</ui-button>
    </ui-dialog>
    `;
    }
    renderValidationError() {
        const { validationError } = this;
        if (!validationError) {
            return '';
        }
        return html `
    <p class="error on-error-text validation-error">
      ${this.validationError}<br/>
      Please, verify the store URI and try again.
    </p>
    `;
    }
    renderProgress() {
        const { validating } = this;
        if (!validating) {
            return '';
        }
        return html `
    <ui-progress indeterminate></ui-progress>
    `;
    }
}
__decorate([
    reactive()
], StoreConfigScreen.prototype, "selected", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "isDefault", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "loadingEnvironments", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "config", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "storeType", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "infoDialogOpened", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "validationError", void 0);
__decorate([
    reactive()
], StoreConfigScreen.prototype, "validating", void 0);
//# sourceMappingURL=StoreConfig.screen.js.map