import React from 'react';
import lbry from '../lbry.js';
import FormField from '../component/form.js';
import {Link} from '../component/link.js';
import Modal from '../component/modal.js';


var publishNumberStyle = {
  width: '50px',
}, publishFieldLabelStyle = {
  display: 'inline-block',
  width: '118px',
  textAlign: 'right',
  verticalAlign: 'top',
}, publishFieldStyle = {
  width: '330px',
};

var PublishPage = React.createClass({
  _requiredFields: ['name', 'bid', 'meta_title', 'meta_author', 'meta_license', 'meta_description'],

  handleSubmit: function(event) {
    if (typeof event !== 'undefined') {
      event.preventDefault();
    }

    this.setState({
      submitting: true,
    });

    var checkFields = this._requiredFields.slice();
    if (!this.state.myClaimExists) {
      checkFields.push('file');
    }

    var missingFieldFound = false;
    for (let fieldName of checkFields) {
      var field = this.refs[fieldName];
      if (field.getValue() === '') {
        field.warnRequired();
        if (!missingFieldFound) {
          field.focus();
          missingFieldFound = true;
        }
      }
    }

    let fileProcessing = false;
    if (this.state.fileInfo && !this.state.tempFileReady) {
      this.refs.file.showAdvice('Your file is still processing.');
      this.refs.file.focus();
      fileProcessing = true;
    }

    if (missingFieldFound || fileProcessing) {
      this.setState({
        submitting: false,
      });
      return;
    }

    if (this.state.nameIsMine) {
      // Pre-populate with existing metadata
      var metadata = Object.assign({}, this.state.myClaimMetadata);
      if (this.refs.file.getValue() !== '') {
        delete metadata.sources;
      }
    } else {
      var metadata = {};
    }

    for (let metaField of ['title', 'author', 'description', 'thumbnail', 'license', 'license_url', 'language', 'nsfw']) {
      var value = this.refs['meta_' + metaField].getValue();
      if (value !== '') {
        metadata[metaField] = value;
      }
    }

    var licenseUrl = this.refs.meta_license_url.getValue();
    if (licenseUrl) {
      metadata.license_url = licenseUrl;
    }

    var doPublish = () => {
      var publishArgs = {
        name: this.state.name,
        bid: parseFloat(this.state.bid),
        metadata: metadata,
      };

      if (this.refs.file.getValue() !== '') {
        publishArgs.file_path = this._tempFilePath;
      }
      
      lbry.publish(publishArgs, (message) => {
        this.handlePublishStarted();
      }, null, (error) => {
        this.handlePublishError(error);
      });
    };

    if (this.state.isFee) {
      lbry.getNewAddress((address) => {
        metadata.fee = {};
        metadata.fee[this.state.feeCurrency] = {
          amount: parseFloat(this.state.feeAmount),
          address: address,
        };

        doPublish();
      });
    } else {
      doPublish();
    }
  },
  getInitialState: function() {
    this._tempFilePath = null;

    return {
      rawName: '',
      name: '',
      bid: '',
      feeAmount: '',
      feeCurrency: 'USD',
      nameResolved: false,
      topClaimValue: 0.0,
      myClaimValue: 0.0,
      myClaimMetadata: null,
      myClaimExists: null,
      fileInfo: null,
      copyrightNotice: '',
      otherLicenseDescription: '',
      otherLicenseUrl: '',
      uploadProgress: 0.0,
      uploaded: false,
      errorMessage: null,
      tempFileReady: false,
      submitting: false,
      modal: null,
    };
  },
  handlePublishStarted: function() {
    this.setState({
      modal: 'publishStarted',
    });
  },
  handlePublishStartedConfirmed: function() {
    window.location = "?published";
  },
  handlePublishError: function(error) {
    this.setState({
      submitting: false,
      modal: 'error',
      errorMessage: error.message,
    });
  },
  handleNameChange: function(event) {
    var rawName = event.target.value;

    if (!rawName) {
      this.setState({
        rawName: '',
        name: '',
        nameResolved: false,
      });

      return;
    }

    if (!lbry.nameIsValid(rawName, false)) {
      this.refs.name.showAdvice('LBRY names must contain only letters, numbers and dashes.');
      return;
    }

    this.setState({
      rawName: rawName,
    });

    var name = rawName.toLowerCase();

    lbry.resolveName(name, (info) => {
      if (name != this.refs.name.getValue().toLowerCase()) {
        // A new name has been typed already, so bail
        return;
      }

      if (!info) {
        this.setState({
          name: name,
          nameResolved: false,
          myClaimExists: false,
        });
      } else {
        lbry.getMyClaim(name, (myClaimInfo) => {
          lbry.getClaimInfo(name, (claimInfo) => {
            if (name != this.refs.name.getValue()) {
              return;
            }

            var topClaimIsMine = (myClaimInfo && myClaimInfo.amount >= claimInfo.amount);

            var newState = {
              name: name,
              nameResolved: true,
              topClaimValue: parseFloat(claimInfo.amount),
              myClaimExists: !!myClaimInfo,
              myClaimValue: parseFloat(myClaimInfo.amount),
              myClaimMetadata: myClaimInfo.value,
              topClaimIsMine: topClaimIsMine,
            };

            if (topClaimIsMine) {
              newState.bid = myClaimInfo.amount;
            } else if (this.state.myClaimMetadata) {
              // Just changed away from a name we have a claim on, so clear pre-fill
              newState.bid = '';
            }

            this.setState(newState);
          });
        });
      }
    });
  },
  handleBidChange: function(event) {
    this.setState({
      bid: event.target.value,
    });
  },
  handleFeeAmountChange: function(event) {
    this.setState({
      feeAmount: event.target.value,
    });
  },
  handleFeeCurrencyChange: function(event) {
    this.setState({
      feeCurrency: event.target.value,
    });
  },
  handleFileChange: function(event) {
    event.preventDefault();

    var fileInput = event.target;

    this._tempFilePath = null;
    if (fileInput.files.length == 0) {
      // File was removed
      this.setState({
        fileInfo: null,
        uploadProgress: 0.0,
        uploaded: false,
        tempFileReady: false,
      });
    } else {
      var file = fileInput.files[0];
      this.setState({
        fileInfo: {
          name: file.name,
          size: file.size,
        },
        uploadProgress: 0.0,
        uploaded: false,
        tempFileReady: false,
      });

      var xhr = new XMLHttpRequest();
      xhr.upload.addEventListener('progress', (event) => {
        this.setState({
          uploadProgress: (event.loaded / event.total),
        });
      });
      xhr.upload.addEventListener('load', (event) => {
        this.setState({
          uploaded: true,
        });
      });
      xhr.addEventListener('load', (event) => {
        this._tempFilePath = JSON.parse(xhr.responseText);
        this.setState({
          tempFileReady: true,
        });
      })

      var formData = new FormData(fileInput.form);
      formData.append('file', fileInput.files[0]);
      xhr.open('POST', lbry.webUiUri + '/upload', true);
      xhr.send(formData);
    }
  },
  handleFeePrefChange: function(feeEnabled) {
    this.setState({
      isFee: feeEnabled
    });
  },
  handeLicenseChange: function(event) {
    var licenseType = event.target.options[event.target.selectedIndex].getAttribute('data-license-type');
    var newState = {
      copyrightChosen: licenseType == 'copyright',
      otherLicenseChosen: licenseType == 'other',
    };

    if (licenseType == 'copyright') {
      var author = this.refs.meta_author.getValue();
      newState.copyrightNotice = 'Copyright ' + (new Date().getFullYear()) + (author ? ' ' + author : '');
    }

    this.setState(newState);
  },
  handleCopyrightNoticeChange: function(event) {
    this.setState({
      copyrightNotice: event.target.value,
    });
  },
  handleOtherLicenseDescriptionChange: function(event) {
    this.setState({
      otherLicenseDescription: event.target.value,
    });
  },
  handleOtherLicenseUrlChange: function(event) {
    this.setState({
      otherLicenseUrl: event.target.value,
    });
  },
  getLicenseUrl: function() {
    if (!this.refs.meta_license) {
      return '';
    } else if (this.state.otherLicenseChosen) {
      return this.state.otherLicenseUrl;
    } else {
      return this.refs.meta_license.getSelectedElement().getAttribute('data-url') || '' ;
    }
  },
  componentDidMount: function() {
    document.title = "Publish";
  },
  componentDidUpdate: function() {
    if (this.state.fileInfo && !this.state.tempFileReady) {
      // A file was chosen but the daemon hasn't finished processing it yet, i.e. it's loading, so
      // we're displaying a progress bar and need a value for it.

      // React can't unset the "value" prop (to show an "indeterminate" bar) after it's already
      // been set, so we have to manage it manually.

      if (!this.state.uploaded) {
        // Still uploading
        this.refs.progress.setAttribute('value', this.state.uploadProgress);
      } else {
        // Fully uploaded and waiting for server to finish processing, so set progress bar to "indeterminite"
        this.refs.progress.removeAttribute('value');
      }
    }
  },
  // Also getting a type warning here too
  render: function() {
    return (
      <main ref="page">
        <form onSubmit={this.handleSubmit}>
          <section className="card">
            <h4>LBRY Name</h4>
            <div className="form-row">
              lbry://<FormField type="text" ref="name" value={this.state.rawName} onChange={this.handleNameChange} />
              {
                (!this.state.name ? '' :
                  (! this.state.nameResolved ? <em> The name <strong>{this.state.name}</strong> is available.</em>
                                             : (this.state.myClaimExists ? <em> You already have a claim on the name <strong>{this.state.name}</strong>. You can use this page to update your claim.</em>
                                                                         : <em> The name <strong>{this.state.name}</strong> is currently claimed for <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit' : 'credits'}.</em>)))
              }
              <div className="help">What LBRY name would you like to claim for this file?</div>
            </div>
          </section>

          <section className="card">
            <h4>Choose File</h4>
            <FormField name="file" ref="file" type="file" onChange={this.handleFileChange} />
            { !this.state.fileInfo ? '' :
                (!this.state.tempFileReady ? <div>
                                               <progress ref='progress'></progress>
                                               {!this.state.uploaded ? <span> Importing file into LBRY...</span> : <span> Processing file...</span>}
                                             </div>
                                           : <div>File ready for publishing!</div>) }
            { this.state.myClaimExists ? <div className="help">If you don't choose a file, the file from your existing claim will be used.</div> : null }
          </section>

          <section className="card">
            <h4>Bid Amount</h4>
            <div className="form-row">
              Credits <FormField ref="bid" style={publishNumberStyle} type="text" onChange={this.handleBidChange} value={this.state.bid} placeholder={this.state.nameResolved ? this.state.topClaimValue + 10 : 100} />
              <div className="help">How much would you like to bid for this name?
              { !this.state.nameResolved ? <span> Since this name is not currently resolved, you may bid as low as you want, but higher bids help prevent others from claiming your name.</span>
                                         : (this.state.topClaimIsMine ? <span> You currently control this name with a bid of <strong>{this.state.myClaimValue}</strong> {this.state.myClaimValue == 1 ? 'credit' : 'credits'}.</span>
                                                                      : (this.state.myClaimExists ? <span> You have a non-winning bid on this name for <strong>{this.state.myClaimValue}</strong> {this.state.myClaimValue == 1 ? 'credit' : 'credits'}.
                                                                                                           To control this name, you'll need to increase your bid to more than <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit' : 'credits'}.</span>
                                                                                                  : <span> You must bid over <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit' : 'credits'} to claim this name.</span>)) }
              </div>
            </div>
          </section>

          <section className="card">
            <h4>Fee</h4>
            <div className="form-row">
              <label>
               <FormField type="radio" onChange={ () => { this.handleFeePrefChange(false) } } checked={!this.state.isFee} /> No fee
              </label>
              <label>
               <FormField type="radio" onChange={ () => { this.handleFeePrefChange(true) } } checked={this.state.isFee} /> { !this.state.isFee ? 'Choose fee...' : 'Fee ' }
               <span className={!this.state.isFee ? 'hidden' : ''}>
                 <FormField type="text" onChange={this.handleFeeAmountChange} style={publishNumberStyle} /> <FormField type="select" onChange={this.handleFeeCurrencyChange}>
                   <option value="USD">US Dollars</option>
                   <option value="LBC">LBRY credits</option>
                 </FormField>
                 </span>
              </label>
              <div className="help">
                <p>How much would you like to charge for this file?</p>
                If you choose to price this content in dollars, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.
              </div>
            </div>
          </section>


          <section className="card">
            <h4>Your Content</h4>

            <div className="form-row">
              <label htmlFor="title">Title</label><FormField type="text" ref="meta_title" name="title" placeholder="My Show, Episode 1" style={publishFieldStyle} />
            </div>
            <div className="form-row">
              <label htmlFor="author">Author</label><FormField type="text" ref="meta_author" name="author" placeholder="My Company, Inc." style={publishFieldStyle} />
            </div>
            <div className="form-row">
            <label htmlFor="license">License</label><FormField type="select" ref="meta_license" name="license" onChange={this.handeLicenseChange}>
              <option data-url="https://creativecommons.org/licenses/by/4.0/legalcode">Creative Commons Attribution 4.0 International</option>
              <option data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode">Creative Commons Attribution-ShareAlike 4.0 International</option>
              <option data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode">Creative Commons Attribution-NoDerivatives 4.0 International</option>
              <option data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode">Creative Commons Attribution-NonCommercial 4.0 International</option>
              <option data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</option>
              <option data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International</option>
              <option>Public Domain</option>
              <option data-license-type="copyright" {... this.state.copyrightChosen ? {value: this.state.copyrightNotice} : {}}>Copyrighted...</option>
              <option data-license-type="other" {... this.state.otherLicenseChosen ? {value: this.state.otherLicenseDescription} : {}}>Other...</option>
            </FormField>
            <FormField type="hidden" ref="meta_license_url" name="license_url" value={this.getLicenseUrl()} />
            </div>
            {this.state.copyrightChosen
              ? <div className="form-row">
                  <label htmlFor="copyright-notice" value={this.state.copyrightNotice}>Copyright notice</label><FormField type="text" name="copyright-notice" value={this.state.copyrightNotice} onChange={this.handleCopyrightNoticeChange} style={publishFieldStyle} />
                </div>
              : null}
            {this.state.otherLicenseChosen
              ? <div className="form-row">
                  <label htmlFor="other-license-description">License description</label><FormField type="text" name="other-license-description" onChange={this.handleOtherLicenseDescriptionChange} style={publishFieldStyle} />
                </div>
              : null}
            {this.state.otherLicenseChosen
              ? <div className="form-row">
                  <label htmlFor="other-license-url">License URL</label> <FormField type="text" name="other-license-url" style={publishFieldStyle} onChange={this.handleOtherLicenseUrlChange} />
                </div>
              : null}

            <div className="form-row">
            <label htmlFor="language">Language</label> <FormField type="select" defaultValue="en" ref="meta_language" name="language">
                 <option value="en">English</option>
                 <option value="zh">Chinese</option>
                 <option value="fr">French</option>
                 <option value="de">German</option>
                 <option value="jp">Japanese</option>
                 <option value="ru">Russian</option>
                 <option value="es">Spanish</option>
              </FormField>
            </div>
            <div className="form-row">
              <label htmlFor="description">Description</label> <FormField type="textarea" ref="meta_description" name="description" placeholder="Description of your content" style={publishFieldStyle} />
            </div>
            <div className="form-row">
              <label><FormField type="checkbox" ref="meta_nsfw" name="nsfw" placeholder="Description of your content" /> Not Safe For Work</label>
            </div>
          </section>



          <section className="card">
            <h4>Additional Content Information (Optional)</h4>
            <div className="form-row">
              <label htmlFor="meta_thumbnail">Thumbnail URL</label> <FormField type="text" ref="meta_thumbnail" name="thumbnail" placeholder="http://mycompany.com/images/ep_1.jpg" style={publishFieldStyle} />
            </div>
          </section>

          <div className="card-series-submit">
           <Link button="primary" label={!this.state.submitting ? 'Publish' : 'Publishing...'} onClick={this.handleSubmit} disabled={this.state.submitting} />
           <Link button="cancel" href="/" label="Cancel"/>
           <input type='submit' className='hidden' />
          </div>
        </form>

        <Modal isOpen={this.state.modal == 'publishStarted'} contentLabel="File published"
               onConfirmed={this.handlePublishStartedConfirmed}>
          <p>Your file has been published to LBRY at the address <code>lbry://{this.state.name}</code>!</p>
          You will now be taken to your My Files page, where your newly published file will be listed. The file will take a few minutes to appear for other LBRY users; until then it will be listed as "pending."
        </Modal>
        <Modal isOpen={this.state.modal == 'error'} contentLabel="Error publishing file"
               onConfirmed={this.closeModal}>
          The following error occurred when attempting to publish your file: {this.state.errorMessage}
        </Modal>
      </main>
    );
  }
});

export default PublishPage;