// @flow
import * as ICONS from 'constants/icons';
import React, { useState, useEffect } from 'react';
import { regexInvalidURI } from 'lbry-redux';
import FileSelector from 'component/common/file-selector';
import Button from 'component/button';
import Card from 'component/common/card';
import Spinner from 'component/spinner';

type Props = {
  name: ?string,
  filePath: string | WebFile,
  isStillEditing: boolean,
  balance: number,
  updatePublishForm: ({}) => void,
  disabled: boolean,
  publishing: boolean,
  showToast: string => void,
  inProgress: boolean,
  clearPublish: () => void,
};

function PublishFile(props: Props) {
  const {
    name,
    balance,
    filePath,
    isStillEditing,
    updatePublishForm,
    disabled,
    publishing,
    inProgress,
    clearPublish,
  } = props;

  const [duration, setDuration] = useState(0);
  const [size, setSize] = useState(0);
  const [oversized, setOversized] = useState(false);
  const [isVid, setIsVid] = useState(false);
  const RECOMMENDED_BITRATE = 8000000;
  const TV_PUBLISH_SIZE_LIMIT: number = 100000000;
  const UPLOAD_SIZE_MESSAGE = 'Lbrytv uploads are limited to 1 GB. Download the app for unrestricted publishing.';

  // clear warnings
  useEffect(() => {
    if (!filePath || filePath === '' || filePath.name === '') {
      setDuration(0);
      setSize(0);
      setIsVid(false);
    }
  }, [filePath]);

  let currentFile = '';
  if (filePath) {
    if (typeof filePath === 'string') {
      currentFile = filePath;
    } else {
      currentFile = filePath.name;
    }
  }

  function getBitrate(size, duration) {
    const s = Number(size);
    const d = Number(duration);
    if (s && d) {
      return (s * 8) / d;
    } else {
      return 0;
    }
  }

  function getMessage() {
    // @if TARGET='web'
    if (oversized || Number(size) > TV_PUBLISH_SIZE_LIMIT) {
      return (
        <p className="help--error">
          {__(UPLOAD_SIZE_MESSAGE)}{' '}
          <Button button="link" label={__('Learn more')} href="https://lbry.com/faq/how-to-publish" />
        </p>
      );
    }
    // @endif
    if (isVid && duration && getBitrate(size, duration) > RECOMMENDED_BITRATE) {
      return (
        <p className="help--error">
          {__('Your video has a bitrate over 8 mbps. We suggest transcoding to provide viewers the best experience.')}{' '}
          <Button button="link" label={__('Learn more')} href="https://lbry.com/faq/how-to-publish" />
        </p>
      );
    }

    if (isVid && !duration) {
      return (
        <p className="help--error">
          {__(
            'Your video may not be the best format. Use MP4s in H264/AAC format and a friendly bitrate (1080p) for more reliable streaming.'
          )}{' '}
          <Button button="link" label={__('Learn more')} href="https://lbry.com/faq/how-to-publish" />
        </p>
      );
    }

    if (!!isStillEditing && name) {
      return (
        <p className="help">
          {__("If you don't choose a file, the file from your existing claim %name% will be used", { name: name })}
        </p>
      );
    }

    if (!isStillEditing) {
      return (
        <p className="help">
          {__(
            'For video content, use MP4s in H264/AAC format and a friendly bitrate (1080p) for more reliable streaming.'
          )}{' '}
          <Button button="link" label={__('Learn more')} href="https://lbry.com/faq/how-to-publish" />
        </p>
      );
    }
  }

  function handleFileChange(file: WebFile) {
    const { showToast } = props;
    window.URL = window.URL || window.webkitURL;
    // if electron, we'll set filePath to the path string because SDK is handling publishing.
    // if web, we set the filePath (dumb name) to the File() object
    // File.path will be undefined from web due to browser security, so it will default to the File Object.
    setSize(file ? file.size : 0);
    setDuration(0);
    setOversized(false);

    // if video, extract duration so we can warn about bitrate
    const isVideo = file.type.split('/')[0] === 'video';
    setIsVid(isVideo);
    if (isVideo) {
      const video = document.createElement('video');
      video.preload = 'metadata';
      video.onloadedmetadata = function() {
        setDuration(video.duration);
        window.URL.revokeObjectURL(video.src);
      };
      video.src = window.URL.createObjectURL(file);
    }

    // @if TARGET='web'
    // we only need to enforce file sizes on 'web'
    if (typeof file !== 'string') {
      if (file && file.size && Number(file.size) > TV_PUBLISH_SIZE_LIMIT) {
        setOversized(true);
        showToast(__(UPLOAD_SIZE_MESSAGE));
        updatePublishForm({ filePath: '', name: '' });
        return;
      }
    }
    // @endif

    const publishFormParams: { filePath: string | WebFile, name?: string } = {
      filePath: file.path || file,
    };
    // Strip off extention and replace invalid characters
    let fileName = name || file.name.substr(0, file.name.lastIndexOf('.')) || file.name;
    let INVALID_URI_CHARS = new RegExp(regexInvalidURI, 'gu');
    let parsedFileName = fileName.replace(INVALID_URI_CHARS, '-');
    if (!isStillEditing) {
      publishFormParams.name = parsedFileName;
    }
    updatePublishForm(publishFormParams);
  }

  let title;
  if (publishing) {
    title = (
      <span>
        {__('Publishing')}
        <Spinner type={'small'} />
      </span>
    );
  } else {
    title = isStillEditing ? __('Edit') : __('Publish');
  }

  return (
    <Card
      actionIconPadding={false}
      icon={ICONS.PUBLISH}
      disabled={disabled || balance === 0}
      title={
        <React.Fragment>
          {title}{' '}
          {inProgress && <Button button="close" label={__('Cancel')} icon={ICONS.REMOVE} onClick={clearPublish} />}
        </React.Fragment>
      }
      subtitle={
        isStillEditing ? __('You are currently editing a claim.') : __('Publish something totally wacky and wild.')
      }
      actions={
        <React.Fragment>
          <FileSelector disabled={disabled} currentPath={currentFile} onFileChosen={handleFileChange} />
          {getMessage()}
        </React.Fragment>
      }
    />
  );
}

export default PublishFile;
