import React from 'react';
import PropTypes from 'prop-types';
import IDUtil from '../../../util/IDUtil';
import ExternalAPI from '../../../api/ExternalAPI';
import { AnnotationEvents } from '../AnnotationClient';
import debounce from 'debounce';

const CUSTOM_API = 'custom';

export default class LinkForm extends React.PureComponent {
    constructor(props) {
        super(props);

        this.config = this.props.annotationClient.config.motivationConfig[
            'link'
        ];

        this.searchTermRef = React.createRef();
        this.linkUrlRef = React.createRef();
        this.linkLabelRef = React.createRef();

        this.debounceSearch = debounce(this.search.bind(this), 400);

        this.state = {
            selectedApi: this.config.apis
                ? this.config.apis[0].name
                : CUSTOM_API,
            results: []
        };
    }

    /* ------------------- CRUD / loading of links ------------------- */

    setApi = e => {
        this.setState({ selectedApi: e.target.value, results: [] }, () => {
            if (this.state.selectedApi !== CUSTOM_API) {
                this.debounceSearch();
            }
        });
    };

    addLink = linkData => {
        if (!linkData) return null;

        // save the link
        this.props.annotationClient.saveBodyElement(
            Object.assign({ annotationType: 'link' }, linkData),
            false,
            true,
            this.props.annotation
        );

        // remove from result set
        this.setState({
            results: this.state.results.filter(result => result !== linkData)
        });
    };

    onInput = e => {
        if (e.charCode == 13) {
            // search right away
            this.search();
        } else {
            // debounced search, automatically
            this.debounceSearch();
        }
    };

    onCustomInput = e => {
        if (e.charCode == 13) {
            this.save();
        }
    };

    isValidURL = url => {
        const urlPattern = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;
        return urlPattern.test(url);
    };

    clear = () => {
        this.searchTermRef.current.value = '';
        this.onSearched([]);
    };

    search = () => {
        // empty term, empty results
        if (!this.searchTermRef.current.value) {
            this.onSearched([]);
            return;
        }

        console.debug('Searching external API');

        // search term set, search
        ExternalAPI.search(
            this.state.selectedApi,
            this.searchTermRef.current.value,
            this.onSearched
        );
    };

    saveCustom = () => {
        if (this.isValidURL(this.linkUrlRef.current.value)) {
            this.addLink({
                url: this.linkUrlRef.current.value,
                label: this.linkLabelRef.current.value
            });
        } else {
            alert('Please enter a valid URL');
        }
    };

    onSearched = results => {
        if (results.error) {
            results = [];
        }
        this.setState({ results: results });
    };

    /* ------------------------------------- RENDER FUNCTIONS --------------------------- */

    renderResultList = searchResults => {
        const results = searchResults.map((res, index) => {
            let poster = null;
            if (res.poster) {
                poster = <img src={res.poster} style={{ maxWidth: '100px' }} />;
            }
            const title = res.label ? res.label : res.title;
            const description =
                title === res.description ? null : res.description;
            return (
                <div
                    key={'result__' + index}
                    className="link-result"
                    title={res.description}
                    onClick={this.addLink.bind(this, res)}
                >
                    <strong>{res.label ? res.label : res.title}</strong>
                    {poster}
                    {description}
                </div>
            );
        });
        return results.length > 0 ? (
            <div className="link-search-results">
                <div className="link-result-list">{results}</div>
                <div onClick={this.clear} className="clear">
                    Clear results
                </div>
            </div>
        ) : null;
    };

    renderApiSelector = (apis, selectedApi, setApiFunc) => {
        const options = apis.map(api => {
            return (
                <option key={api.name} value={api.name}>
                    {api.name}
                </option>
            );
        });

        return (
            <div className="filter">
                <strong>API:</strong>
                <select onChange={setApiFunc} value={selectedApi}>
                    {options}
                </select>
            </div>
        );
    };

    renderFormFields = (onInput, showClear) => {
        const fields = (
            <div key="l_api" className="link-row input-row">
                <strong>Search: </strong>
                <input
                    type="text"
                    ref={this.searchTermRef}
                    placeholder="Search through the selected API"
                    onInput={onInput}
                />
                {showClear && (
                    <div
                        className="clear"
                        title="Clear search results"
                        onClick={this.clear}
                    />
                )}
            </div>
        );

        return <div className="link-form">{fields}</div>;
    };

    renderCustomFormFields = onInput => {
        const fields = [
            <div key="l_url" className="link-row">
                <strong>URL</strong>
                <input type="text" ref={this.linkUrlRef} onInput={onInput} />
            </div>,
            <div key="l_label" className="link-row">
                <strong>Label</strong>
                <input type="text" ref={this.linkLabelRef} onInput={onInput} />
            </div>
        ];

        return <div className="link-form">{fields}</div>;
    };

    //TODO replace all the bootstrap stuff
    render() {
        //draw the list of search results
        const resultList = this.renderResultList(this.state.results);

        //draw radio buttons for selecting an API
        const apiSelect = this.renderApiSelector(
            this.config.apis || [],
            this.state.selectedApi,
            this.setApi
        );

        //draw a URL and link label field (custom mode) OR draw a search field (if an API is selected)
        const formFields =
            this.state.selectedApi == CUSTOM_API
                ? this.renderCustomFormFields(this.onCustomInput)
                : this.renderFormFields(
                      this.onInput,
                      this.searchTermRef.current &&
                          this.searchTermRef.current.value
                  );

        return (
            <div className={IDUtil.cssClassName('link-form')}>
                {apiSelect}
                {formFields}
                {resultList}
            </div>
        );
    }
}

LinkForm.propTypes = {
    annotationClient: PropTypes.object.isRequired,
    annotation: PropTypes.object.isRequired
};
