import { LoadingSpinner } from '@sourcegraph/react-loading-spinner';
import { isEqual, upperFirst } from 'lodash';
import CheckIcon from 'mdi-react/CheckIcon';
import CloseIcon from 'mdi-react/CloseIcon';
import PowerPlugIcon from 'mdi-react/PowerPlugIcon';
import React from 'react';
import { Link } from 'react-router-dom';
import { forkJoin, Subject } from 'rxjs';
import { catchError, distinctUntilChanged, map, switchMap } from 'rxjs/operators';
import { EMODENOTFOUND, fetchServerCapabilities } from '../../backend/lsp';
import { PLAINTEXT_MODE } from '../../util';
import { asError, isErrorLike } from '../../util/errors';
import { fetchLangServer } from './backend';
function hasCrossRepositoryCodeIntelligence(capabilities) {
    return !!capabilities.xdefinitionProvider && !!capabilities.xworkspaceReferencesProvider;
}
const CapabilityStatus = ({ label, provided }) => (React.createElement("li", null,
    provided ? (React.createElement(CheckIcon, { className: "icon-inline text-success" })) : (React.createElement(CloseIcon, { className: "icon-inline text-danger" })),
    ' ',
    label));
const propsToStateUpdate = (obs) => obs.pipe(distinctUntilChanged((a, b) => a.mode === b.mode), switchMap(({ repoPath, rev, commitID, filePath, mode }) => {
    if (!mode) {
        return [null];
    }
    return forkJoin(fetchLangServer(mode), fetchServerCapabilities({ repoPath, rev, commitID, filePath, mode }).pipe(catchError(err => {
        if (err.code === EMODENOTFOUND) {
            return [undefined];
        }
        else {
            throw err;
        }
    }))).pipe(map(([langServer, capabilities]) => langServer && {
        displayName: langServer.displayName,
        homepageURL: langServer.homepageURL || undefined,
        issuesURL: langServer.issuesURL || undefined,
        experimental: langServer.experimental,
        capabilities,
    }), catchError(err => [asError(err)]));
}), map(langServerOrError => ({ langServerOrError })));
export class CodeIntelStatusIndicator extends React.Component {
    constructor() {
        super(...arguments);
        this.state = {};
        this.componentUpdates = new Subject();
        this.subscription = this.componentUpdates
            .pipe(propsToStateUpdate)
            .subscribe(stateUpdate => this.setState(stateUpdate));
    }
    shouldComponentUpdate(nextProps, nextState) {
        return (!isEqual(this.state, nextState) ||
            this.props.userIsSiteAdmin !== nextProps.userIsSiteAdmin ||
            this.props.mode !== nextProps.mode);
    }
    componentDidMount() {
        this.componentUpdates.next(this.props);
    }
    componentDidUpdate(oldProps) {
        this.componentUpdates.next(this.props);
    }
    componentWillUnmount() {
        this.subscription.unsubscribe();
    }
    getButtonColorCSSClass() {
        if (this.state.langServerOrError === undefined) {
            return '';
        }
        if (this.state.langServerOrError === null ||
            isErrorLike(this.state.langServerOrError) ||
            !this.state.langServerOrError.capabilities) {
            return 'text-danger';
        }
        if (!this.state.langServerOrError.capabilities.hoverProvider ||
            !this.state.langServerOrError.capabilities.referencesProvider ||
            !this.state.langServerOrError.capabilities.definitionProvider ||
            this.state.langServerOrError.experimental ||
            !hasCrossRepositoryCodeIntelligence(this.state.langServerOrError.capabilities)) {
            return 'text-warning';
        }
        return 'text-success';
    }
    render() {
        return (React.createElement("div", { className: "code-intel-status-indicator" },
            React.createElement("a", { className: `code-intel-status-indicator__icon nav-link ${this.getButtonColorCSSClass()}`, tabIndex: 0 },
                React.createElement(PowerPlugIcon, { className: "icon-inline" })),
            React.createElement("div", { className: "code-intel-status-indicator__popover card", tabIndex: -1 },
                React.createElement("div", { className: "card-body" }, this.state.langServerOrError === undefined ? (React.createElement("div", { className: "text-center" },
                    React.createElement(LoadingSpinner, { className: "icon-inline" }))) : isErrorLike(this.state.langServerOrError) ? (React.createElement("span", { className: "text-danger" }, upperFirst(this.state.langServerOrError.message))) : this.state.langServerOrError === null ? (this.props.mode === PLAINTEXT_MODE ? ('No code intelligence available on plain text files.') : (React.createElement(React.Fragment, null,
                    React.createElement("h3", null, "No language server connected"),
                    "Check",
                    ' ',
                    React.createElement("a", { href: "http://langserver.org/", target: "_blank" }, "langserver.org"),
                    ' ',
                    "for ",
                    this.props.mode,
                    " language servers."))) : !this.state.langServerOrError.capabilities ? (React.createElement(React.Fragment, null,
                    React.createElement("h3", null,
                        "The ",
                        this.state.langServerOrError.displayName || this.props.mode,
                        " language server is disabled"),
                    this.props.userIsSiteAdmin ? (React.createElement(React.Fragment, null,
                        "You can enable the ",
                        this.state.langServerOrError.displayName || this.props.mode,
                        ' ',
                        "language server on the",
                        ' ',
                        React.createElement(Link, { to: "/site-admin/code-intelligence" }, "code intelligence administration page"),
                        ".")) : (React.createElement(React.Fragment, null,
                        "Ask your site admin to enable the",
                        ' ',
                        this.state.langServerOrError.displayName || this.props.mode,
                        " language server.")))) : (React.createElement(React.Fragment, null,
                    React.createElement("h3", null,
                        "Connected to the ",
                        React.createElement("wbr", null),
                        React.createElement("a", { href: this.state.langServerOrError.homepageURL, target: "_blank" },
                            this.state.langServerOrError.displayName || this.props.mode,
                            " language server")),
                    React.createElement("h4", { className: "mt-2 mb-0" }, "Provides:"),
                    React.createElement("ul", { className: "list-unstyled" },
                        React.createElement(CapabilityStatus, { label: "Hovers", provided: !!this.state.langServerOrError.capabilities.hoverProvider }),
                        React.createElement(CapabilityStatus, { label: "Definitions", provided: !!this.state.langServerOrError.capabilities.definitionProvider }),
                        React.createElement(CapabilityStatus, { label: "References", provided: !!this.state.langServerOrError.capabilities.referencesProvider }),
                        React.createElement(CapabilityStatus, { label: "Implementations", provided: !!this.state.langServerOrError.capabilities.implementationProvider })),
                    React.createElement("h4", { className: "mt-2 mb-0" }, "Scope:"),
                    React.createElement("ul", { className: "list-unstyled" },
                        React.createElement(CapabilityStatus, { label: "Local", provided: true }),
                        React.createElement(CapabilityStatus, { label: "Cross-repository", provided: hasCrossRepositoryCodeIntelligence(this.state.langServerOrError.capabilities) })),
                    this.state.langServerOrError.experimental && (React.createElement("p", { className: "mt-2 mb-0 text-warning font-weight-light" },
                        React.createElement("em", null, "This language server is experimental - some code intelligence actions might not work correctly."))
                    // TODO - Add docs link about experimental code intelligence when written
                    ),
                    this.props.userIsSiteAdmin && (React.createElement("p", { className: "mt-2 mb-0" },
                        React.createElement(Link, { to: "/site-admin/code-intelligence" }, "Manage"))),
                    this.state.langServerOrError.issuesURL && (React.createElement("p", { className: "mt-2 mb-0" },
                        React.createElement("a", { href: this.state.langServerOrError.issuesURL, target: "_blank" }, "Report issue")))))))));
    }
}
//# sourceMappingURL=CodeIntelStatusIndicator.js.map