import * as React from 'react';
import * as _ from 'lodash-es';

import { K8sResourceKind, K8sResourceKindReference } from '../module/k8s';
import { ImageStreamTagModel } from '../models';
import { DetailsPage } from './factory';
import { Kebab, SectionHeading, navFactory, ResourceSummary } from './utils';
import { humanizeBinaryBytes } from './utils/units';
import { ExampleDockerCommandPopover } from './image-stream';
import { ImageStreamTimeline } from './image-stream-timeline';

const ImageStreamTagsReference: K8sResourceKindReference = 'ImageStreamTag';
const ImageStreamsReference: K8sResourceKindReference = 'ImageStream';

const { common } = Kebab.factory;
const menuActions = [...Kebab.getExtensionsActionsForKind(ImageStreamTagModel), ...common];

// Splits a name/value pair separated by an `=`
const splitEnv = (nameValue: string) => {
  // Use this method instead of `String.split()` so we only split on the first `=`.
  const i = nameValue.indexOf('=');
  if (i === -1) {
    return {
      name: nameValue,
      value: '',
    };
  }

  return {
    name: nameValue.substring(0, i),
    value: nameValue.substring(i + 1),
  };
};

export const ImageStreamTagsDetails: React.SFC<ImageStreamTagsDetailsProps> = ({
  obj: imageStreamTag,
  imageStream,
}) => {
  const config = _.get(imageStreamTag, 'image.dockerImageMetadata.Config', {});
  const labels = config.Labels || {};
  // Convert to an array of objects with name and value properties, then sort the array for display.
  const labelsArray = _.map(labels, (value, name) => ({ name, value }));
  const sortedLabels = _.sortBy(labelsArray, 'name');
  const entrypoint = (config.Entrypoint || []).join(' ');
  const cmd = (config.Cmd || []).join(' ');
  const exposedPorts = _.keys(config.ExposedPorts).join(', ');
  const size = _.get(imageStreamTag, 'image.dockerImageMetadata.Size');
  const humanizedSize = _.isFinite(size) && humanizeBinaryBytes(size).string;
  const architecture = _.get(imageStreamTag, 'image.dockerImageMetadata.Architecture');
  const tagName = _.get(imageStreamTag, 'tag.name');

  return (
    <div className="co-m-pane__body">
      <div className="co-m-pane__body-group">
        <div className="row">
          <div className="col-md-6 col-sm-12">
            <SectionHeading text="Image Overview" />
            <ResourceSummary resource={imageStreamTag}>
              {labels.name && <dt>Image Name</dt>}
              {labels.name && <dd>{labels.name}</dd>}
              {labels.summary && <dt>Summary</dt>}
              {labels.summary && <dd>{labels.summary}</dd>}
              {humanizedSize && <dt>Size</dt>}
              {humanizedSize && <dd>{humanizedSize}</dd>}
            </ResourceSummary>
            <ExampleDockerCommandPopover imageStream={imageStream} tag={tagName} />
          </div>
          <div className="col-md-6 col-sm-12">
            <SectionHeading text="Configuration" />
            <dl className="co-m-pane__details">
              {entrypoint && <dt>Entrypoint</dt>}
              {entrypoint && <dd className="co-break-word">{entrypoint}</dd>}
              {cmd && <dt>Command</dt>}
              {cmd && <dd className="co-break-word">{cmd}</dd>}
              {config.WorkingDir && <dt>Working Dir</dt>}
              {config.WorkingDir && <dd className="co-break-all">{config.WorkingDir}</dd>}
              {exposedPorts && <dt>Exposed Ports</dt>}
              {exposedPorts && <dd className="co-break-word">{exposedPorts}</dd>}
              {config.User && <dt>User</dt>}
              {config.User && <dd>{config.User}</dd>}
              {architecture && <dt>Architecture</dt>}
              {architecture && <dd>{architecture}</dd>}
            </dl>
          </div>
        </div>
      </div>
      <div className="co-m-pane__body-group">
        <SectionHeading text="Image Labels" />
        {_.isEmpty(sortedLabels) ? (
          <span className="text-muted">No labels</span>
        ) : (
          <div className="co-table-container">
            <table className="table">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Value</th>
                </tr>
              </thead>
              <tbody>
                {_.map(sortedLabels, ({ name, value }) => (
                  <tr key={name}>
                    <td>{name}</td>
                    <td>{value}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
      <div className="co-m-pane__body-group">
        <SectionHeading text="Environment Variables" />
        {_.isEmpty(config.Env) ? (
          <span className="text-muted">No environment variables</span>
        ) : (
          <div className="co-table-container">
            <table className="table">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Value</th>
                </tr>
              </thead>
              <tbody>
                {_.map(config.Env, (nameValueStr, i) => {
                  const pair = splitEnv(nameValueStr);
                  return (
                    <tr key={i}>
                      <td>{pair.name}</td>
                      <td>{pair.value}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  );
};

const parseName = (nameAndTag: string): string => {
  return nameAndTag.split(':')[0];
};

const getImageStreamNameAndTag = (imageStreamTag: K8sResourceKind) => {
  const imageStreamTagName: string = _.get(imageStreamTag, 'metadata.name') || '';
  const [imageStreamName, tag] = imageStreamTagName.split(':');
  return { imageStreamName, tag };
};

const ImageStreamTagHistory: React.FC<ImageStreamTagHistoryProps> = ({
  obj: imageStreamTag,
  imageStream,
}) => {
  const { tag } = getImageStreamNameAndTag(imageStreamTag);
  const imageStreamStatusTags = _.filter(_.get(imageStream, 'status.tags'), (i) => i.tag === tag);
  return (
    <ImageStreamTimeline
      imageStreamTags={imageStreamStatusTags}
      imageStreamName={imageStream.metadata.name}
      imageStreamNamespace={imageStream.metadata.namespace}
    />
  );
};
ImageStreamTagHistory.displayName = 'ImageStreamTagHistory';

const pages = [
  navFactory.details(ImageStreamTagsDetails),
  navFactory.editYaml(),
  navFactory.history(ImageStreamTagHistory),
];
export const ImageStreamTagsDetailsPage: React.SFC<ImageStreamTagsDetailsPageProps> = (props) => (
  <DetailsPage
    {...props}
    breadcrumbsFor={(obj) => {
      const { imageStreamName } = getImageStreamNameAndTag(obj);
      return [
        { name: 'Image Streams', path: `/k8s/ns/${props.match.params.ns}/imagestreams` },
        {
          name: imageStreamName,
          path: `/k8s/ns/${props.match.params.ns}/imagestreams/${imageStreamName}`,
        },
        {
          name: 'Image Stream Tag Details',
          path: props.match.url,
        },
      ];
    }}
    kind={ImageStreamTagsReference}
    menuActions={menuActions}
    resources={[
      {
        kind: ImageStreamsReference,
        name: parseName(props.name),
        namespace: props.namespace,
        isList: false,
        prop: 'imageStream',
      },
    ]}
    pages={pages}
  />
);
ImageStreamTagsDetailsPage.displayName = 'ImageStreamTagsDetailsPage';

type ImageStreamTagHistoryProps = {
  imageStream: K8sResourceKind;
  obj: K8sResourceKind;
};

export type ImageStreamTagsDetailsProps = {
  obj: K8sResourceKind;
  imageStream: K8sResourceKind;
};

export type ImageStreamTagsDetailsPageProps = {
  match: any;
  namespace: string;
  name: string;
};
