import { LoadingSpinner } from '@sourcegraph/react-loading-spinner';
import { upperFirst } from 'lodash';
import CheckIcon from 'mdi-react/CheckIcon';
import LockIcon from 'mdi-react/LockIcon';
import * as React from 'react';
import { Link } from 'react-router-dom';
import { interval, Subject, Subscription } from 'rxjs';
import { catchError, distinctUntilChanged, filter, map, startWith, switchMap, takeUntil, tap } from 'rxjs/operators';
import { FeedbackText } from '../../components/FeedbackText';
import { PageTitle } from '../../components/PageTitle';
import { Timestamp } from '../../components/time/Timestamp';
import { checkMirrorRepositoryConnection, updateMirrorRepository } from '../../site-admin/backend';
import { eventLogger } from '../../tracking/eventLogger';
import { DirectImportRepoAlert } from '../DirectImportRepoAlert';
import { fetchRepository } from './backend';
import { ActionContainer, BaseActionContainer } from './components/ActionContainer';
class UpdateMirrorRepositoryActionContainer extends React.PureComponent {
    constructor() {
        super(...arguments);
        this.componentUpdates = new Subject();
        this.subscriptions = new Subscription();
        this.updateMirrorRepository = () => {
            const p = updateMirrorRepository({ repository: this.props.repo.id })
                .toPromise()
                .then(result => this.props.onDidUpdateRepository());
            return p;
        };
    }
    componentDidMount() {
        // If repository is cloning, poll until it's done.
        this.subscriptions.add(this.componentUpdates
            .pipe(startWith(this.props), map(props => props.repo.mirrorInfo), distinctUntilChanged((a, b) => a.cloneInProgress === b.cloneInProgress && a.cloned === b.cloned), filter(mirrorInfo => mirrorInfo.cloneInProgress || !mirrorInfo.cloned), switchMap(() => interval(3000).pipe(takeUntil(this.componentUpdates.pipe(filter(props => !props.repo.mirrorInfo.cloneInProgress && props.repo.mirrorInfo.cloned))))))
            .subscribe(repo => this.props.onDidUpdateRepository()));
    }
    componentWillReceiveProps(props) {
        this.componentUpdates.next(props);
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        let title;
        let description;
        let buttonLabel;
        let buttonDisabled = false;
        let info;
        if (this.props.repo.mirrorInfo.cloneInProgress) {
            title = 'Cloning in progress...';
            description =
                React.createElement("code", null, this.props.repo.mirrorInfo.cloneProgress) ||
                    'This repository is currently being cloned from its remote repository.';
            buttonLabel = (React.createElement("span", null,
                React.createElement(LoadingSpinner, { className: "icon-inline" }),
                " Cloning..."));
            buttonDisabled = true;
            info = React.createElement(DirectImportRepoAlert, { className: "action-container__alert" });
        }
        else if (this.props.repo.mirrorInfo.cloned) {
            title = (React.createElement(React.Fragment, null,
                "Last refreshed:",
                ' ',
                this.props.repo.mirrorInfo.updatedAt ? (React.createElement(Timestamp, { date: this.props.repo.mirrorInfo.updatedAt })) : ('unknown'),
                ' '));
            description =
                'This repository is automatically updated from its remote repository periodically and when accessed by a user.';
            buttonLabel = 'Refresh now';
        }
        else {
            title = 'Clone this repository';
            description = 'This repository has not yet been cloned from its remote repository.';
            buttonLabel = 'Clone now';
        }
        return (React.createElement(ActionContainer, { title: title, description: React.createElement("div", null, description), buttonLabel: buttonLabel, buttonDisabled: buttonDisabled || this.props.disabled, buttonSubtitle: this.props.disabledReason, flashText: "Added to queue", info: info, run: this.updateMirrorRepository }));
    }
}
class CheckMirrorRepositoryConnectionActionContainer extends React.PureComponent {
    constructor() {
        super(...arguments);
        this.state = { loading: false };
        this.checkRequests = new Subject();
        this.subscriptions = new Subscription();
        this.checkMirrorRepositoryConnection = () => this.checkRequests.next();
    }
    componentDidMount() {
        this.subscriptions.add(this.checkRequests
            .pipe(tap(() => {
            this.setState({ errorDescription: undefined, result: undefined, loading: true });
            this.props.onDidUpdateReachability(undefined);
        }), switchMap(() => checkMirrorRepositoryConnection({ repository: this.props.repo.id }).pipe(catchError(error => {
            this.setState({ errorDescription: error.message, result: undefined, loading: false });
            this.props.onDidUpdateReachability(false);
            return [];
        }))))
            .subscribe(result => {
            this.setState({ result, loading: false });
            this.props.onDidUpdateReachability(result.error === null);
        }, error => console.log(error)));
        // Run the check upon initial mount, so the user sees the information without needing to click.
        this.checkRequests.next();
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        return (React.createElement(BaseActionContainer, { title: "Check connection to remote repository", description: React.createElement("span", null, "Diagnose problems cloning or updating from the remote repository."), action: React.createElement("button", { className: "btn btn-primary", disabled: this.state.loading, onClick: this.checkMirrorRepositoryConnection }, "Check connection"), details: React.createElement(React.Fragment, null,
                this.state.errorDescription && (React.createElement("div", { className: "alert alert-danger action-container__alert" },
                    "Error: ",
                    this.state.errorDescription)),
                this.state.loading && (React.createElement("div", { className: "alert alert-primary action-container__alert" },
                    React.createElement(LoadingSpinner, { className: "icon-inline" }),
                    " Checking connection...")),
                this.state.result &&
                    (this.state.result.error === null ? (React.createElement("div", { className: "alert alert-success action-container__alert" },
                        React.createElement(CheckIcon, { className: "icon-inline" }),
                        " The remote repository is reachable.")) : (React.createElement("div", { className: "alert alert-danger action-container__alert" },
                        React.createElement("p", null, "The remote repository is unreachable. Logs follow."),
                        React.createElement("div", null,
                            React.createElement("pre", { className: "check-mirror-repository-connection-action-container__log" },
                                React.createElement("code", null, this.state.result.error))))))) }));
    }
}
/**
 * The repository settings mirror page.
 */
export class RepoSettingsMirrorPage extends React.PureComponent {
    constructor(props) {
        super(props);
        this.repoUpdates = new Subject();
        this.subscriptions = new Subscription();
        this.onDidUpdateRepository = () => {
            this.repoUpdates.next();
            this.props.onDidUpdateRepository({});
        };
        this.onDidUpdateReachability = (reachable) => this.setState({ reachable });
        this.state = {
            loading: false,
            repo: props.repo,
        };
    }
    componentDidMount() {
        eventLogger.logViewEvent('RepoSettingsMirror');
        this.subscriptions.add(this.repoUpdates
            .pipe(switchMap(() => fetchRepository(this.props.repo.name)))
            .subscribe(repo => this.setState({ repo }), err => this.setState({ error: err.message })));
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        return (React.createElement("div", { className: "repo-settings-mirror-page" },
            React.createElement(PageTitle, { title: "Mirror settings" }),
            React.createElement("h2", null, "Mirroring and cloning"),
            this.state.loading && React.createElement(LoadingSpinner, { className: "icon-inline" }),
            this.state.error && React.createElement("div", { className: "alert alert-danger" }, upperFirst(this.state.error)),
            React.createElement("div", { className: "form-group" },
                React.createElement("label", null,
                    "Remote repository URL",
                    ' ',
                    React.createElement("small", { className: "text-info" },
                        React.createElement(LockIcon, { className: "icon-inline" }),
                        " Only visible to site admins")),
                React.createElement("input", { className: "form-control", value: this.props.repo.mirrorInfo.remoteURL || '(unknown)', readOnly: true }),
                React.createElement("small", { className: "form-text text-muted" },
                    "Configure repository mirroring in",
                    ' ',
                    this.state.repo.viewerCanAdminister ? (React.createElement(Link, { to: "/site-admin/configuration" }, "site configuration")) : ('site configuration'),
                    ".")),
            React.createElement(UpdateMirrorRepositoryActionContainer, { repo: this.state.repo, onDidUpdateRepository: this.onDidUpdateRepository, disabled: typeof this.state.reachable === 'boolean' && !this.state.reachable, disabledReason: typeof this.state.reachable === 'boolean' && !this.state.reachable ? 'Not reachable' : undefined }),
            React.createElement(CheckMirrorRepositoryConnectionActionContainer, { repo: this.state.repo, onDidUpdateReachability: this.onDidUpdateReachability }),
            typeof this.state.reachable === 'boolean' &&
                !this.state.reachable && (React.createElement("div", { className: "alert alert-info repo-settings-mirror-page__troubleshooting" },
                "Problems cloning or updating this repository?",
                React.createElement("ul", { className: "repo-settings-mirror-page__steps" },
                    React.createElement("li", { className: "repo-settings-mirror-page__step" },
                        "Inspect the ",
                        React.createElement("strong", null, "Check connection"),
                        " error log output to see why the remote repository is not reachable."),
                    React.createElement("li", { className: "repo-settings-mirror-page__step" },
                        React.createElement("code", null,
                            React.createElement("strong", null, "No ECDSA host key is known ... Host key verification failed?")),
                        ' ',
                        "See",
                        ' ',
                        React.createElement("a", { href: "https://about.sourcegraph.com/docs/server/config/repositories#ssh-authentication-config-keys-known_hosts" }, "SSH repository authentication documentation"),
                        ' ',
                        "for how to provide an SSH ",
                        React.createElement("code", null, "known_hosts"),
                        " file with the remote host's SSH host key."),
                    React.createElement("li", { className: "repo-settings-mirror-page__step" },
                        "Consult",
                        ' ',
                        React.createElement("a", { href: "https://about.sourcegraph.com/docs/server/config/repositories" }, "Sourcegraph repositories documentation"),
                        ' ',
                        "for resolving other authentication issues (such as HTTPS certificates and SSH keys)."),
                    React.createElement("li", { className: "repo-settings-mirror-page__step" },
                        React.createElement(FeedbackText, { headerText: "Questions?" })))))));
    }
}
//# sourceMappingURL=RepoSettingsMirrorPage.js.map