import React from 'react';
import PropTypes from 'prop-types';
import copy from 'clipboard-copy';

import Flex from '@ui/components/Flex';
import Tabs from '@ui/components/Tabs';
import Table from '@ui/components/Table';
import Title from '@ui/components/Title';
import Button from '@ui/components/Button';
import HTTPStatus from '@ui/components/HTTPStatus';
import ShowMore from '@ui/components/ShowMore';

// Style
let classes = {};
/* istanbul ignore next */
if (typeof window !== 'undefined' || typeof _COMPILED_ === 'undefined') classes = require('./style.module.scss');

const WrapValuesInCode = h => {
  if (typeof h.value === 'string')
    h.value = (
      <pre key={`H::${h.name}`} className={classes['APILog-tableValue']}>
        {h.value}
      </pre>
    );
};

const copyHandler = async ({ target }, body) => {
  const copied = await copy(body)
    .then(() => 'OK')
    .catch(() => 'ERR');
  const modifier = classes[`APILog-copy_${copied}`];
  target.classList.add(modifier);
  setTimeout(() => target.classList.remove(modifier), 2500);
};

const ToggleHeaders = ({ text, theme = 'shale' }) => (
  <Flex layout="row">
    <small>
      <Button bem={{ [theme]: true }} size="sm">
        {text}
      </Button>
    </small>
  </Flex>
);
ToggleHeaders.propTypes = { text: PropTypes.string, theme: PropTypes.string };

const APILogInfo = ({ link, method, startedDateTime, status, url }) => {
  const datetime = startedDateTime ? new Date(startedDateTime) : false;
  return (
    <React.Fragment>
      <div shift="end" style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
        <b>
          <HTTPStatus status={status} /> <code>{method}</code>
        </b>{' '}
        <code>{url}</code>{' '}
      </div>
      {!datetime || (
        <span style={{ opacity: 0.75, textAlign: 'right' }}>
          {datetime.toLocaleDateString('en-US', { dateStyle: 'short' })}
          {', '}
          {datetime.toLocaleTimeString('en-US', { timeStyle: 'short' }).replace(' ', '')}
        </span>
      )}
      {!link || (
        <a href={link} rel="noopener noreferrer" style={{ whiteSpace: 'nowrap' }} target="_blank">
          <b>View Docs</b>
        </a>
      )}
    </React.Fragment>
  );
};
APILogInfo.propTypes = {
  link: PropTypes.string,
  method: PropTypes.string,
  startedDateTime: PropTypes.string,
  status: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  url: PropTypes.string,
};

const APILogRequest = ({ headers = [], allHeaders = [], query, curl }) => {
  headers.forEach(WrapValuesInCode);
  allHeaders.forEach(WrapValuesInCode);
  query.forEach(WrapValuesInCode);

  return (
    <React.Fragment>
      <Title level={5}>Body</Title>
      <div style={{ position: 'relative' }}>
        <Button
          bem={{ shale: !0 }}
          className={classes['APILog-copy']}
          onClick={e => copyHandler(e, curl)}
          size="sm"
          text="Copy"
        />
        <pre>{curl}</pre>
      </div>

      <Title level={5}>Headers</Title>
      <div>
        {headers.length > 0 && <Table body={headers} pick={['name', 'value']} />}
        {!allHeaders.length || (
          <ShowMore
            height="8em"
            label={<ToggleHeaders text="All..." />}
            labelClose={<ToggleHeaders text="Less..." theme="shale_ghost" />}
          >
            <Table body={allHeaders} pick={['name', 'value']} />
          </ShowMore>
        )}
      </div>

      {(query.length && (
        <React.Fragment>
          <Title level={5}>Query Parameters</Title>
          <Table body={query} pick={['name', 'value']} />
        </React.Fragment>
      )) ||
        ''}
    </React.Fragment>
  );
};
APILogRequest.propTypes = {
  allHeaders: PropTypes.array,
  curl: PropTypes.string,
  headers: PropTypes.array,
  query: PropTypes.array,
};

const APILogResponse = ({ headers = [], allHeaders = [], json }) => {
  const body = JSON.stringify(JSON.parse(json), null, 2);

  headers.forEach(WrapValuesInCode);
  allHeaders.forEach(WrapValuesInCode);

  return (
    <React.Fragment>
      <Title level={5}>Body</Title>
      <div style={{ position: 'relative' }}>
        <Button
          bem={{ shale: !0 }}
          className={classes['APILog-copy']}
          onClick={e => copyHandler(e, body)}
          size="sm"
          text="Copy"
        />
        <pre>{body}</pre>
      </div>

      <Title level={5}>Headers</Title>
      <div>
        {/* istanbul ignore next */ !headers.length || <Table body={headers} pick={['name', 'value']} />}
        {!allHeaders.length || (
          <ShowMore
            height="8em"
            label={<ToggleHeaders text="All..." theme="shale_ghost" />}
            labelClose={<ToggleHeaders text="Less..." />}
          >
            <Table body={allHeaders} pick={['name', 'value']} />
          </ShowMore>
        )}
      </div>
    </React.Fragment>
  );
};
APILogResponse.propTypes = {
  allHeaders: PropTypes.array,
  headers: PropTypes.array,
  json: PropTypes.string,
};

class APILog extends React.Component {
  static propTypes = {
    link: PropTypes.string,
    log: PropTypes.shape({
      curl: PropTypes.string,
      fullReqHeaders: PropTypes.array,
      fullResHeaders: PropTypes.array,
      method: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      queryString: PropTypes.array,
      requestHeaders: PropTypes.array,
      response: PropTypes.object,
      responseBody: PropTypes.object,
      responseHeaders: PropTypes.array,
      startedDateTime: PropTypes.string,
      status: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      url: PropTypes.string,
    }),
  };

  constructor(props) {
    super(props);
    this.curl = props.log.curl || 'No cURL available.';
  }

  render() {
    const { log, link } = this.props;
    const { status, startedDateTime = '', requestHeaders, queryString, method, url } = log;
    return (
      <Flex align="stretch" className={classes.APILog} layout="col" style={this.props.style}>
        <Flex align="center" className={classes['APILog-info']}>
          <APILogInfo link={link} method={method} startedDateTime={startedDateTime} status={status} url={url} />
        </Flex>

        <Tabs className={{ root: 'Flex_inner', tabs: classes['APILog-tabs'] }}>
          <div label="Request">
            <APILogRequest
              allHeaders={log.fullReqHeaders}
              curl={this.curl}
              headers={requestHeaders}
              query={queryString}
            />
          </div>
          <div label="Response">
            <APILogResponse
              allHeaders={log.fullResHeaders}
              headers={log.responseHeaders}
              json={log.responseBody.text}
            />
          </div>
        </Tabs>
      </Flex>
    );
  }
}

export default APILog;
