import { formatDistance } from 'date-fns';
import { isEqual, truncate } from 'lodash';
import * as React from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import { merge, of, Subject, Subscription } from 'rxjs';
import { catchError, delay, switchMap, takeUntil } from 'rxjs/operators';
import { asError, isErrorLike } from '../../../util/errors';
import { fetchBlameFile2 } from './backend';
const LOADING = 'loading';
/** The time in ms after which to show a loader if the result has not returned yet */
const LOADER_DELAY = 100;
export class BlameLine extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            content: '',
            href: '#',
        };
        this.portal = null;
        /** Emits with the latest Props on every componentDidUpdate and on componentDidMount */
        this.componentUpdates = new Subject();
        /** Subscriptions to be disposed on unmount */
        this.subscriptions = new Subscription();
        this.subscriptions.add(this.componentUpdates
            .pipe(switchMap(props => {
            const blameFetch = fetchBlameFile2({
                repoPath: props.repoPath,
                commitID: props.commitID,
                filePath: props.filePath,
                line: props.line,
            }).pipe(catchError((error) => [asError(error)]));
            return merge(blameFetch, of(LOADING).pipe(delay(LOADER_DELAY), takeUntil(blameFetch)));
        }))
            .subscribe(hunksOrError => {
            let content;
            let href = '#';
            if (hunksOrError === LOADING) {
                content = 'loading ◌';
            }
            else if (isErrorLike(hunksOrError)) {
                content = 'blame error: ' + hunksOrError.message;
            }
            else {
                const hunk = hunksOrError[0];
                // rev is actually the commitID
                const commitID = truncate(hunk.rev, { length: 7, omission: '' });
                const message = truncate(hunk.message, { length: 80, omission: '…' });
                const timeSince = formatDistance(hunk.author.date, new Date(), { addSuffix: true });
                content = `${hunk.author.person.name}, ${timeSince} • ${message} ${commitID}`;
                href = hunk.commit.url;
            }
            this.setState({ content, href });
        }));
    }
    shouldComponentUpdate(nextProps, nextState) {
        return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
    }
    componentDidMount() {
        this.portal = document.getElementById(this.props.portalID);
        this.componentUpdates.next(this.props);
    }
    componentDidUpdate() {
        this.componentUpdates.next(this.props);
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    render() {
        if (!this.portal) {
            return null;
        }
        return ReactDOM.createPortal(React.createElement(Link, { className: "blame", to: this.state.href },
            React.createElement("span", { className: "blame__contents", "data-contents": this.state.content })), this.portal);
    }
}
//# sourceMappingURL=BlameLine.js.map