/* eslint no-param-reassign: 0 */
import React, { Component } from 'react';
import ToggleIcon from './toggle-icon.jsx';
import AthletePanel from './athlete-panel.jsx';

import SportsIcon from '@material-ui/icons/Sports';
import FootballIcon from '@material-ui/icons/SportsFootball';
import BaseballIcon from '@material-ui/icons/SportsBaseball';
import BasketballIcon from '@material-ui/icons/SportsBasketball';

import AthleteIcon from '@material-ui/icons/AccountCircle';
import AltImage from './alt-image.jsx';

import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';

//const nlp = require("../node_modules/spacy-nlp/src/nlp")
const fetch = require('node-fetch');
const io = require("socket.io-client");

import window from 'global';

let lastMentioned;

const grammarNames = require('../config/grammar-names.json');

const defaultAthlete = {displayJersey: '', displayDraft: '', status: {name: ''}, team: {name: '', displayName: '', logos: [{href: ''}], color: '#000'}, statsSummary: {statistics: []}};
const defaultDbAthlete = {id: '', name: {first: '', last: '', display: ''}, position: '', jersey: '', height: 0, weight: 0, dateofbirth: '', college: ''};

const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const SpeechGrammarList = window.SpeechGrammarList || window.webkitSpeechGrammarList;

console.log('gotit', SpeechRecognition);

const leagueSports = {
  mlb: 'baseball',
  nba: 'basketball',
  nfl: 'football'
};

const sportsLeagues = {
  baseball: 'mlb',
  basketball: 'nba',
  football: 'nfl'
};

const sports = [
  'baseball', 'football', 'basketball'
];

const sportsTriggers = {
  baseball: new RegExp('\W' + [
    'baseball', 'RBI', 'base hits', 'at bat', 'ground ball','home run','batted','walks','pitch','strikeout','stolen bases','batting average','on base','slugging','slugger', 'batted',
    'pitcher', 'catcher', 'right field', 'left field', 'center field', 'short stop', 'foul ball', 'hitter'
  ].join('|')),
  basketball: new RegExp('\W' + [
    'basketball', 'point guard', 'shooting guard', 'small forward', 'power forward',
    'assist', 'shooting', 'shooter', 'rebound', 'free throw', 'technical foul', 'double double', 'triple double', 'flagrant', 'dribble', 'court'
  ].join('|')),
  football: new RegExp('\W' + [
    'football', 'quarterback', 'runningback', 'halfback', 'receiver', 'tight end', 'left tackle', 'right tackle', 'left guard', 'right guard', 'defensive end', 'left end', 'right end', 'defensive tackle', 'linebacker', 'safety', 'cornerback', 'kicker', 'punter',
    'completions','passing attempt','passing yards','touchdown','interception','sacks','fumble','QB rating', 'tackle', 'receptions', 'rushing'
  ].join('|'))
};

const hasUpperRegex1 = new RegExp('[A-Z]');
const hasUpperRegex2 = new RegExp('[A-Z]\\w+\\s[A-Z]\\w+');

export class Demo extends Component {
  constructor(props) {
    super();
    this.state = {
      rawMessages: [],
      formattedMessages: [],
      listening: false,
      keywords: '',
      error: null,
      currentAthlete: defaultAthlete,
      dbAthlete: defaultDbAthlete,
      speechReady: false,
      subject: null,
      recognition: null,
      autoRestart: false,
      restarting: false,
      alternateAthletes: null,
      sportAnchorEl: null,
      altAnchorEl: null,
      messageFinalized: true
    };
    
    this.handleSportClick = this.handleSportClick.bind(this);
    this.handleSportChoice = this.handleSportChoice.bind(this);
    this.handleSportClose = this.handleSportClose.bind(this);
    this.handleAltClick = this.handleAltClick.bind(this);
    this.handleAltClose = this.handleAltClose.bind(this);

    this.reset = this.reset.bind(this);
    this.stopTranscription = this.stopTranscription.bind(this);
    this.handleMicClick = this.handleMicClick.bind(this);
    this.handleRawMessage = this.handleRawMessage.bind(this);
    this.handleFormattedMessage = this.handleFormattedMessage.bind(this);
    this.handleError = this.handleError.bind(this);
    
    this.recognitionStart = this.recognitionStart.bind(this);
    this.recognitionEnd = this.recognitionEnd.bind(this);
    this.recognitionResult = this.recognitionResult.bind(this);
    this.recognitionError = this.recognitionError.bind(this);
    
    this.fetchPlayer = this.fetchPlayer.bind(this);
  }
  
  componentDidMount() {
    //this.initSocket();
    
    if (SpeechRecognition) {
      const grammar = '#JSGF V1.0; grammar names; public <name> = ' + grammarNames.join(' | ') + ' | <otherNames> ;';
      console.log('ready to recognize', grammar);
      const speechRecognitionList = new SpeechGrammarList();
      speechRecognitionList.addFromString(grammar, 1);

      this.setState({speechReady: true, recognition: new SpeechRecognition()}, () => {
        const { recognition } = this.state;
        
        recognition.continuous = true;
        recognition.interimResults = true;
        recognition.grammars = speechRecognitionList;
        
        recognition.onstart = this.recognitionStart;
        recognition.onend = this.recognitionEnd;
        recognition.onresult = this.recognitionResult;
        recognition.onerror = this.recognitionError;
      });
    }
    else {
      console.log('cant recognize');
    }
  }
  
  
  recognitionStart() {
    console.log('LISTENING...');
    this.setState({ listening: true, autoRestart: true });
  }
  
  recognitionEnd(ev) {
    console.log('ENDED', ev);
    if (this.state.autoRestart) {
      console.log('RESTART1');
      this.state.recognition.start();
      return;
    }
    this.setState({ listening: false, autoRestart: false });
  }
  
  recognitionResult(ev) {
    const results = ev.results;
    //console.log(results.length, results);
    
    if (typeof(results) == 'undefined') {
      recognition.onend = null;
      recognition.stop();
      console.log('browser does not support');
      return;
    }
    
    let interimText = '',
        finalText = '';
    for (var i = ev.resultIndex; i < results.length; ++i) {
      //console.log('result ' + i, results[i].isFinal, parseInt(ev.timeStamp), results[i][0])
      if (results[i].isFinal) {
        finalText += results[i][0].transcript;
      } else {
        interimText += results[i][0].transcript;
      }
    }
    if (interimText.length)
      this.handleRawMessage(interimText);
    if (finalText.length)
      this.handleFormattedMessage(finalText);
      
    //console.log('interim', interimText);
    //console.log('final', finalText);
  }
  
  recognitionError(event) {
    console.error(event);
    if (event.error === 'no-speech' && this.state.autoRestart) {
      console.log('RESTART2');
      this.state.recognition.start();
      return;
    }
    else if (event.error === 'aborted') {
      return;
    }
    this.setState({ listening: false, speechReady: false, autoRestart: false });
  }
  
  handleSportClick(ev) {
    ev.preventDefault();
    this.setState({sportAnchorEl: ev.currentTarget || ev.target});
  }
  
  handleSportChoice(idx) {
    console.log('sportchoice', idx)
    this.setState({sportAnchorEl: null, subject: sports[idx]});
  }

  handleSportClose(ev) {
    ev.preventDefault();
    console.log('sportclose', ev.currentTarget, ev);
    if (this.state.sportAnchorEl)
      this.setState({sportAnchorEl: null});
  }
  
  handleAltClick(ev) {
    ev.preventDefault();
    console.log('altclick', ev.currentTarget, ev.target);
    this.setState({altAnchorEl: ev.currentTarget || ev.target});
  }

  handleAltClose(ev) {
    ev.preventDefault();
    
    const choiceData = ev.currentTarget.dataset;
    console.log('altclose', choiceData, ev.currentTarget);
    this.fetchPlayer(choiceData.id, choiceData.sport, choiceData.league);
    this.setState({altAnchorEl: null, alternateAthletes: null});
  }
  
  /*
  initSocket() {
    this.socket = io('http://localhost:3001');
    
    this.socket.on('dbResponse', (results, started) => {
      console.log('yay', results, (new Date().getTime()-started));
      if (results.length)
        this.setState({dbAthlete: results[0]});
    });
    
    this.socket.on('proxy-client-loaded', (data, started) => {
      console.log('CLIENT LOADED!');
    });
    this.socket.on('direct-test', data => {
      console.log('direct socket confirmed! DATA', data);
    });
    
    this.socket.on('data', this.handleFormattedMessage);
    
    this.socket.on('end', this.handleTranscriptEnd);
    this.socket.on('error', this.handleError);

    this.socket.on('message', (frame, json) => this.handleRawMessage({ sent: false, frame, json }));
    this.socket.on('send-json', json => this.handleRawMessage({ sent: true, json }))
    this.socket.on('close', (code, message) => this.handleRawMessage({ close: true, code, message }));
  }
  */

  reset() {
    if (this.state.listening) {
      console.log('stop1');
      this.stopTranscription();
    }
    this.setState({ rawMessages: [], formattedMessages: [], error: null });
  }

  stopTranscription() {
    this.setState({autoRestart: false}, () => {
      this.state.recognition.abort();
    });
  }

  handleMicClick(ev) {
    console.log('micclick', ev);
    if (this.state.listening) {
      console.log('stop2');
      this.stopTranscription();
      return;
    }
    this.reset();
    this.state.recognition.start();

    //this.handleStream(recognizeMicrophone(this.getRecognizeOptions()));
  }

  async handleRawMessage(text) {
    //const { rawMessages } = this.state;
    //this.setState({ rawMessages: rawMessages.concat(msg) });
    
    //var text = "I think Tom Brady is great";
    const nlpStart = new Date().getTime();
    console.log('interim: ' + nlpStart, text);
    //console.log('parsed message', text);
    
    //const result = await nlp.parse_named_entities(text, ['word']);
    
    if (hasUpperRegex2.test(text)) {
      console.log('HAS UPPER2');
      //nlp.parse_named_entities(text, ["words"]).then(output => {
        //console.log('output', (new Date().getTime() - nlpStart), output);
        //if (output[0].result.length) {
          //const mentioned = output[0].result[0];
          
          const output = hasUpperRegex2.exec(text);
          const mentioned = output[0];
          
          console.log('mentioned', mentioned, new Date().getTime());
          if (mentioned !== lastMentioned) {
            lastMentioned = mentioned;
            
            this.setState({currentAthlete: defaultAthlete, dbAthlete: defaultDbAthlete, alternateAthletes: null});
            
            //this.socket.emit('dbQuery', {name: mentioned, started: new Date().getTime()});
            var startLookup = new Date().getTime();
            
            fetch('https://www.googleapis.com/customsearch/v1?key=AIzaSyCtY0Ysdb7hL1o3d2eIkNFKQfzh6vg9l08&cx=d452d0da4f98a9c81&q=' + encodeURIComponent(mentioned))
            	.then(resp => resp.json())
            	.then(json => {
            	  console.log('lookup took', (new Date().getTime() - startLookup) + 'ms')
            	  if (json.items && json.items.length) {
            	    let alreadyFound = false;
            	    let alts = [];
            	    let primaryAthlete
            	    for (let i=0; i<10; ++i) {
                	  const searchResult = json.items[i];
                	  //console.log(searchResult.title, searchResult);
                	  
                	  if (searchResult.title.indexOf('Stats, News, Bio | ESPN') !== -1) {
                	    const linkSplit = searchResult.link.split('/');
                	    const playerID = linkSplit[7];
                	    const playerLeague = linkSplit[3];
                	    const playerSport = leagueSports[playerLeague];
                	    
                	    console.log('found', playerID, playerSport, playerLeague, searchResult);
                	    
                	    if (alreadyFound) {
                	      alts.push({
                	        name: searchResult.title.replace(' Stats, News, Bio | ESPN', ''),
                	        id: playerID,
                	        sport: playerSport,
                	        league: playerLeague
                	      });
                	    }
                	    else {
                  	    this.fetchPlayer(playerID, playerSport, playerLeague);
                      	alreadyFound = true;
                	    }
                	  }
            	    }
            	    console.log('ALTERNATIVE RESULTS', alts);
            	    if (alts.length)
            	      this.setState({alternateAthletes: alts});
            	  }
            	});
          }
        //}
        //console.log(JSON.stringify(output[0].parse_tree, null, 2));
      //});
    }
  }
  
  fetchPlayer(playerId, playerSport, playerLeague) {
    fetch('https://site.web.api.espn.com/apis/common/v3/sports/' + playerSport + '/' + playerLeague + '/athletes/' + playerId + '/')
  	.then(resp => resp.json())
  	.then(json => {
  	  if (json && json.athlete) {
  	    json.athlete.leagueInfo = json.league;
  	    json.athlete.leagueInfo.lowerAbbr = playerLeague;
    	  //console.log(json.athlete);
    	  this.setState({currentAthlete: json.athlete});
  	  }
  	});
  }

  handleFormattedMessage(text) {
    //console.log('formatted?', msg)
    //console.log('raw message', msg.json.results[0].alternatives[0].transcript)
    
    console.log('final: ' + new Date().getTime(), text);
    
    if (sportsTriggers.football.test(text))
      this.setState({subject: 'football'});
    else if (sportsTriggers.baseball.test(text))
      this.setState({subject: 'baseball'});
    else if (sportsTriggers.basketball.test(text))
      this.setState({subject: 'basketball'});
  }


  handleError(err, extra) {
    console.error(err, extra);
    this.setState({ error: err.message || err });
  }

  render() {
    const {
      listening, error, formattedMessages, altAnchorEl, sportAnchorEl,
      currentAthlete, dbAthlete, speechReady, alternateAthletes, subject
    } = this.state;

    
    let micButtonClass = 'mic-button';
    if (speechReady) {
      if (listening)
        micButtonClass += ' mic-button--active';
      else
        micButtonClass += ' mic-button--ready';
    }
    else {
      micButtonClass += ' mic-button--disabled';
    }
    
    let micWrapClass = 'mic-button-wrap';
    if (currentAthlete.status.name) {
      micWrapClass += ' move-to-bottom';
    }
    
    const altAthleteEls = (alternateAthletes) ? alternateAthletes.map((athlete, i) =>
      <MenuItem key={i} onClick={this.handleAltClose} data-id={athlete.id} data-sport={athlete.sport} data-league={athlete.league} className="search_results__item">
        <div className="search_results__link detailed">
          <div className="search_results__img headshot-sm athlete">
             <AltImage src={'https://a1.espncdn.com/combiner/i?img=/i/headshots/' + athlete.league + '/players/full/' + athlete.id + '.png&amp;w=80&amp;h=80&amp;scale=crop&amp;cquality=40'} />
          </div>
          <div className="search_results__details">
            <span className="search_results__label">{athlete.name}</span>
            <span className="search_results__cat">{athlete.league.toUpperCase()}</span>
          </div>
        </div>
      </MenuItem>
    ) : '';
    
    const sportsEls = sports.map((sport, idx) => (
      <MenuItem key={idx} onClick={(ev) => this.handleSportChoice(idx)}>{sport}</MenuItem>
    ));

    const err = error
      ? (
        <Alert type="error" color="red">
          <p className="base--p">
            {error}
          </p>
        </Alert>
      )
      : null;
    
    
    const shouldRender = (dbAthlete.name.first || currentAthlete.status.name) ? 'true' : 'false'
    console.log('render check ', altAnchorEl);

    return (
      <div>
        {err}

        {false &&
          <Tabs selected={0} style={{display: "none"}}>
            <Pane label="Text">
              <Transcript messages={messages} />
            </Pane>
            <Pane label="Keywords">
              <Keywords
                messages={messages}
                isInProgress={listening}
              />
            </Pane>
          </Tabs>
        }
        
        { (dbAthlete.name.first || currentAthlete.status.name) && <AthletePanel info={currentAthlete} dbInfo={dbAthlete} /> }
        
        
        <div className="bottom-fixed-btn-wrap" style={{left: 24}}>
          <Button aria-controls="sport-menu" aria-haspopup="true" onClick={this.handleSportClick}>
            {subject === 'baseball' ?
                <BaseballIcon style={{width: '100%', height: '100%'}} />
              : subject === 'football' ?
                <FootballIcon style={{width: '100%', height: '100%'}} />
              : subject === 'basketball' ?
                <BasketballIcon style={{width: '100%', height: '100%'}} />
              :
                <SportsIcon style={{width: '100%', height: '100%'}} />
            }
          </Button>
          <Menu
            id="sport-menu"
            anchorEl={sportAnchorEl}
            keepMounted
            open={Boolean(sportAnchorEl)}
            onClose={this.handleSportClose}
          >{sportsEls}</Menu>
        </div>
              
        
        <div className={micWrapClass}>
          <button type="button" className={micButtonClass} onClick={this.handleMicClick}>
            <ToggleIcon listening={listening} />
          </button>
        </div>
        { alternateAthletes &&
          <div className="bottom-fixed-btn-wrap" style={{right: 24}}>
            <Button aria-controls="alt-athlete-menu" aria-haspopup="true" onClick={this.handleAltClick}>
              <AthleteIcon style={{width: '100%', height: '100%'}} />
            </Button>
            <div className="search_results__suggestions search_results__suggestions--cat">
              <Menu
                id="alt-athlete-menu"
                anchorEl={altAnchorEl}
                keepMounted
                open={Boolean(altAnchorEl)}
                onClose={this.handleAltClose}
              >{altAthleteEls}</Menu>
            </div>
          </div>
        }
      </div>
    );
  }
};

export default Demo;