import { gqlToCascade } from '@sourcegraph/extensions-client-common/lib/settings';
import { upperFirst } from 'lodash';
import AlertCircleIcon from 'mdi-react/AlertCircleIcon';
import MapSearchIcon from 'mdi-react/MapSearchIcon';
import * as React from 'react';
import { Route, Switch } from 'react-router';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { catchError, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
import { gql, queryGraphQL } from '../backend/graphql';
import { HeroPage } from '../components/HeroPage';
import settingsSchemaJSON from '../schema/settings.schema.json';
import { createAggregateError, isErrorLike } from '../util/errors';
import { SettingsPage } from './SettingsPage';
const NotFoundPage = () => React.createElement(HeroPage, { icon: MapSearchIcon, title: "404: Not Found" });
const LOADING = 'loading';
/**
 * A settings area with a top-level JSON editor and sub-pages for editing nested settings values.
 */
export class SettingsArea extends React.Component {
    constructor() {
        super(...arguments);
        this.state = { dataOrError: LOADING };
        this.subjectChanges = new Subject();
        this.refreshRequests = new Subject();
        this.subscriptions = new Subscription();
        this.onUpdate = () => this.refreshRequests.next();
    }
    componentDidMount() {
        // Load settings.
        this.subscriptions.add(combineLatest(this.subjectChanges, this.refreshRequests.pipe(startWith(void 0)))
            .pipe(distinctUntilChanged(), switchMap(([{ id }]) => fetchConfigurationCascade(id).pipe(switchMap(cascade => this.getMergedSettingsJSONSchema(cascade).pipe(map(settingsJSONSchema => ({ subjects: cascade.subjects, settingsJSONSchema })))), catchError(error => [error]), map(c => ({ dataOrError: c })))))
            .subscribe(stateUpdate => this.setState(stateUpdate), err => console.error(err)));
        this.subjectChanges.next(this.props.subject);
    }
    componentWillReceiveProps(props) {
        if (props.subject !== this.props.subject) {
            this.subjectChanges.next(props.subject);
        }
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        if (this.state.dataOrError === LOADING) {
            return null; // loading
        }
        if (isErrorLike(this.state.dataOrError)) {
            return (React.createElement(HeroPage, { icon: AlertCircleIcon, title: "Error", subtitle: upperFirst(this.state.dataOrError.message) }));
        }
        let term;
        switch (this.props.subject.__typename) {
            case 'User':
                term = 'User';
                break;
            case 'Org':
                term = 'Organization';
                break;
            case 'Site':
                term = 'Global';
                break;
            default:
                term = 'Unknown';
                break;
        }
        const transferProps = {
            data: this.state.dataOrError,
            subject: this.props.subject,
            authenticatedUser: this.props.authenticatedUser,
            onUpdate: this.onUpdate,
            isLightTheme: this.props.isLightTheme,
            extensions: this.props.extensions,
        };
        return (React.createElement(React.Fragment, null,
            React.createElement("h2", null,
                term,
                " settings"),
            this.props.extraHeader,
            React.createElement(Switch, null,
                React.createElement(Route, { path: this.props.match.url, key: "hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
                    , exact: true, 
                    // tslint:disable-next-line:jsx-no-lambda
                    render: routeComponentProps => React.createElement(SettingsPage, Object.assign({}, routeComponentProps, transferProps)) }),
                React.createElement(Route, { key: "hardcoded-key", component: NotFoundPage }))));
    }
    getMergedSettingsJSONSchema(cascade) {
        return this.props.extensions.withRegistryMetadata(gqlToCascade(cascade)).pipe(map(configuredExtensions => ({
            $id: 'sourcegraph://merged-settings.schema.json',
            allOf: [
                settingsSchemaJSON,
                ...configuredExtensions
                    .map(ce => {
                    if (ce.manifest &&
                        !isErrorLike(ce.manifest) &&
                        ce.manifest.contributes &&
                        ce.manifest.contributes.configuration) {
                        return ce.manifest.contributes.configuration;
                    }
                    return true; // JSON Schema that matches everything
                })
                    .filter(schema => schema !== true),
            ],
        })));
    }
}
function fetchConfigurationCascade(subject) {
    return queryGraphQL(gql `
            query ConfigurationCascade($subject: ID!) {
                configurationSubject(id: $subject) {
                    configurationCascade {
                        subjects {
                            latestSettings {
                                id
                                configuration {
                                    contents
                                }
                            }
                        }
                    }
                }
            }
        `, { subject }).pipe(map(({ data, errors }) => {
        if (!data || !data.configurationSubject) {
            throw createAggregateError(errors);
        }
        return data.configurationSubject.configurationCascade;
    }));
}
//# sourceMappingURL=SettingsArea.js.map