import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import ReactTable from 'react-table';
import { saveAs } from 'file-saver/FileSaver';
import escapeRegExp from 'lodash/escapeRegExp';
import endsWith from 'lodash/endsWith';
import { Trans, withNamespaces } from 'react-i18next';

import { formatTime } from '../../helpers/helpers';
import { getTrackerData } from '../../helpers/trackers/trackers';
import PageTitle from '../ui/PageTitle';
import Card from '../ui/Card';
import Loading from '../ui/Loading';
import PopoverFiltered from '../ui/PopoverFilter';
import Popover from '../ui/Popover';
import './Logs.css';

const DOWNLOAD_LOG_FILENAME = 'dns-logs.txt';

class Logs extends Component {
    componentDidMount() {
        this.getLogs();
        this.props.getFilteringStatus();
    }

    componentDidUpdate(prevProps) {
        // get logs when queryLog becomes enabled
        if (this.props.dashboard.queryLogEnabled && !prevProps.dashboard.queryLogEnabled) {
            this.props.getLogs();
        }
    }

    getLogs = () => {
        // get logs on initialization if queryLogIsEnabled
        if (this.props.dashboard.queryLogEnabled) {
            this.props.getLogs();
        }
    }

    renderTooltip(isFiltered, rule, filter) {
        if (rule) {
            return (isFiltered && <PopoverFiltered rule={rule} filter={filter}/>);
        }
        return '';
    }

    toggleBlocking = (type, domain) => {
        const { userRules } = this.props.filtering;
        const { t } = this.props;
        const lineEnding = !endsWith(userRules, '\n') ? '\n' : '';
        const baseRule = `||${domain}^$important`;
        const baseUnblocking = `@@${baseRule}`;
        const blockingRule = type === 'block' ? baseUnblocking : baseRule;
        const unblockingRule = type === 'block' ? baseRule : baseUnblocking;
        const preparedBlockingRule = new RegExp(`(^|\n)${escapeRegExp(blockingRule)}($|\n)`);
        const preparedUnblockingRule = new RegExp(`(^|\n)${escapeRegExp(unblockingRule)}($|\n)`);

        if (userRules.match(preparedBlockingRule)) {
            this.props.setRules(userRules.replace(`${blockingRule}`, ''));
            this.props.addSuccessToast(`${t('rule_removed_from_custom_filtering_toast')}: ${blockingRule}`);
        } else if (!userRules.match(preparedUnblockingRule)) {
            this.props.setRules(`${userRules}${lineEnding}${unblockingRule}\n`);
            this.props.addSuccessToast(`${t('rule_added_to_custom_filtering_toast')}: ${unblockingRule}`);
        }

        this.props.getFilteringStatus();
    }

    renderBlockingButton(isFiltered, domain) {
        const buttonClass = isFiltered ? 'btn-outline-secondary' : 'btn-outline-danger';
        const buttonText = isFiltered ? 'unblock_btn' : 'block_btn';
        const buttonType = isFiltered ? 'unblock' : 'block';

        return (
            <div className="logs__action">
                <button
                    type="button"
                    className={`btn btn-sm ${buttonClass}`}
                    onClick={() => this.toggleBlocking(buttonType, domain)}
                >
                    <Trans>{buttonText}</Trans>
                </button>
            </div>
        );
    }

    renderLogs(logs) {
        const { t } = this.props;
        const columns = [{
            Header: t('time_table_header'),
            accessor: 'time',
            maxWidth: 110,
            filterable: false,
            Cell: ({ value }) => (<div className="logs__row"><span className="logs__text" title={value}>{formatTime(value)}</span></div>),
        }, {
            Header: t('domain_name_table_header'),
            accessor: 'domain',
            Cell: (row) => {
                const response = row.value;
                const trackerData = getTrackerData(response);

                return (
                    <div className="logs__row" title={response}>
                        <div className="logs__text">
                            {response}
                        </div>
                        {trackerData && <Popover data={trackerData}/>}
                    </div>
                );
            },
        }, {
            Header: t('type_table_header'),
            accessor: 'type',
            maxWidth: 60,
        }, {
            Header: t('response_table_header'),
            accessor: 'response',
            Cell: (row) => {
                const responses = row.value;
                const { reason } = row.original;
                const isFiltered = row ? reason.indexOf('Filtered') === 0 : false;
                const parsedFilteredReason = reason.replace('Filtered', 'Filtered by ');
                const rule = row && row.original && row.original.rule;
                const { filterId } = row.original;
                const { filters } = this.props.filtering;
                let filterName = '';

                if (reason === 'FilteredBlackList' || reason === 'NotFilteredWhiteList') {
                    if (filterId === 0) {
                        filterName = t('custom_filter_rules');
                    } else {
                        const filterItem = Object.keys(filters)
                            .filter(key => filters[key].id === filterId);

                        if (typeof filterItem !== 'undefined' && typeof filters[filterItem] !== 'undefined') {
                            filterName = filters[filterItem].name;
                        }

                        if (!filterName) {
                            filterName = t('unknown_filter', { filterId });
                        }
                    }
                }

                if (isFiltered) {
                    return (
                        <div className="logs__row">
                            <span className="logs__text" title={parsedFilteredReason}>
                                {parsedFilteredReason}
                            </span>
                            {this.renderTooltip(isFiltered, rule, filterName)}
                        </div>
                    );
                }

                if (responses.length > 0) {
                    const liNodes = responses.map((response, index) =>
                        (<li key={index} title={response}>{response}</li>));
                    const isRenderTooltip = reason === 'NotFilteredWhiteList';

                    return (
                        <div className="logs__row">
                            <ul className="list-unstyled">{liNodes}</ul>
                            {this.renderTooltip(isRenderTooltip, rule, filterName)}
                        </div>
                    );
                }
                return (
                    <div className="logs__row">
                        <span><Trans>empty_response_status</Trans></span>
                        {this.renderTooltip(isFiltered, rule, filterName)}
                    </div>
                );
            },
            filterMethod: (filter, row) => {
                if (filter.value === 'filtered') {
                    // eslint-disable-next-line no-underscore-dangle
                    return row._original.reason.indexOf('Filtered') === 0 || row._original.reason === 'NotFilteredWhiteList';
                }
                return true;
            },
            Filter: ({ filter, onChange }) =>
                <select
                    onChange={event => onChange(event.target.value)}
                    className="form-control"
                    value={filter ? filter.value : 'all'}
                >
                    <option value="all">{ t('show_all_filter_type') }</option>
                    <option value="filtered">{ t('show_filtered_type') }</option>
                </select>,
        }, {
            Header: t('client_table_header'),
            accessor: 'client',
            maxWidth: 250,
            Cell: (row) => {
                const { reason } = row.original;
                const isFiltered = row ? reason.indexOf('Filtered') === 0 : false;

                return (
                    <Fragment>
                        <div className="logs__row">
                            {row.value}
                        </div>
                        {this.renderBlockingButton(isFiltered, row.original.domain)}
                    </Fragment>
                );
            },
        },
        ];

        if (logs) {
            return (<ReactTable
                className='logs__table'
                filterable
                data={logs}
                columns={columns}
                showPagination={true}
                defaultPageSize={50}
                minRows={7}
                // Text
                previousText={ t('previous_btn') }
                nextText={ t('next_btn') }
                loadingText={ t('loading_table_status') }
                pageText={ t('page_table_footer_text') }
                ofText={ t('of_table_footer_text') }
                rowsText={ t('rows_table_footer_text') }
                noDataText={ t('no_logs_found') }
                defaultFilterMethod={(filter, row) => {
                    const id = filter.pivotId || filter.id;
                    return row[id] !== undefined ?
                        String(row[id]).indexOf(filter.value) !== -1 : true;
                }}
                defaultSorted={[
                    {
                        id: 'time',
                        desc: true,
                    },
                ]}
                getTrProps={(_state, rowInfo) => {
                    // highlight filtered requests
                    if (!rowInfo) {
                        return {};
                    }

                    if (rowInfo.original.reason.indexOf('Filtered') === 0) {
                        return {
                            className: 'red',
                        };
                    } else if (rowInfo.original.reason === 'NotFilteredWhiteList') {
                        return {
                            className: 'green',
                        };
                    }

                    return {
                        className: '',
                    };
                }}
                />);
        }
        return undefined;
    }

    handleDownloadButton = async (e) => {
        e.preventDefault();
        const data = await this.props.downloadQueryLog();
        const jsonStr = JSON.stringify(data);
        const dataBlob = new Blob([jsonStr], { type: 'text/plain;charset=utf-8' });
        saveAs(dataBlob, DOWNLOAD_LOG_FILENAME);
    };

    renderButtons(queryLogEnabled) {
        if (queryLogEnabled) {
            return (
                <Fragment>
                    <button
                        className="btn btn-gray btn-sm mr-2"
                        type="submit"
                        onClick={() => this.props.toggleLogStatus(queryLogEnabled)}
                    ><Trans>disabled_log_btn</Trans></button>
                    <button
                        className="btn btn-primary btn-sm mr-2"
                        type="submit"
                        onClick={this.handleDownloadButton}
                    ><Trans>download_log_file_btn</Trans></button>
                    <button
                        className="btn btn-outline-primary btn-sm"
                        type="submit"
                        onClick={this.getLogs}
                    ><Trans>refresh_btn</Trans></button>
                </Fragment>
            );
        }

        return (
            <button
                className="btn btn-success btn-sm mr-2"
                type="submit"
                onClick={() => this.props.toggleLogStatus(queryLogEnabled)}
            ><Trans>enabled_log_btn</Trans></button>
        );
    }

    render() {
        const { queryLogs, dashboard, t } = this.props;
        const { queryLogEnabled } = dashboard;
        return (
            <Fragment>
                <PageTitle title={ t('query_log') } subtitle={ t('last_dns_queries') }>
                    <div className="page-title__actions">
                        {this.renderButtons(queryLogEnabled)}
                    </div>
                </PageTitle>
                <Card>
                    {queryLogEnabled && queryLogs.getLogsProcessing && <Loading />}
                    {queryLogEnabled && !queryLogs.getLogsProcessing &&
                        this.renderLogs(queryLogs.logs)}
                </Card>
            </Fragment>
        );
    }
}

Logs.propTypes = {
    getLogs: PropTypes.func,
    queryLogs: PropTypes.object,
    dashboard: PropTypes.object,
    toggleLogStatus: PropTypes.func,
    downloadQueryLog: PropTypes.func,
    getFilteringStatus: PropTypes.func,
    filtering: PropTypes.object,
    userRules: PropTypes.string,
    setRules: PropTypes.func,
    addSuccessToast: PropTypes.func,
    t: PropTypes.func,
};

export default withNamespaces()(Logs);