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

import Snackbar from '@material-ui/core/Snackbar';
import MuiAlert from '@material-ui/lab/Alert';

const teamData = require('../config/team-data.json');

//const nlp = require("../node_modules/spacy-nlp/src/nlp")
const fetch = require('node-fetch');
import window from 'global';

let lastMentionsInterim = [];

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([
    'baseball', 'MLB', '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([
    'basketball', 'NBA', 'point guard', 'shooting guard', 'small forward', 'power forward',
    'assist', 'shooting', 'shooter', 'rebound', 'free throw', 'technical foul', 'double double', 'triple double', 'flagrant', 'dribble', 'court', 'three pointers', 'jumper'
  ].join('|')),
  football: new RegExp([
    'football', 'NFL', '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','yards','touchdown','interception','sacks','fumble','QB rating', 'quarterback rating', 'tackle', 'receptions', 'rushing'
  ].join('|'))
};

let teamNames = {};
for (let sport in teamData) {
  for (let league in teamData[sport]) {
    teamNames[league] = {};
    let teams = teamData[sport][league];
    for (let ti in teams) {
      teamNames[league][teams[ti].displayName] = {sport: sport, idx: ti};
    }
  }
}

const hasUpperRegex = new RegExp('(?:[A-Z][\\w-]+\\s?){2,3}');
const lookupRegex = new RegExp('look\\s?up((?:\\s[A-Z][\\w-]+){2,3}|(?:(?:\\s[\\w-]+){2}))');

let interimMentions = {};

export default class SpeechProcessor extends Component {
  constructor(props) {
    super();
    this.state = {
      rawMessages: [],
      formattedMessages: [],
      listening: false,
      keywords: '',
      error: null,
      speechReady: false,
      recognition: null,
      autoRestart: false,
      restarting: false,
      alternateAthletes: null,
      messageFinalized: true
    };

    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.handleCloseInfo = this.handleCloseInfo.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');
    }
  }
  
  componentDidUpdate(prevProps) {
    if (window.location.search.includes('bg')) {
      if (this.props.teamName) {
        if (this.props.teamName !== prevProps.teamName) {
          const bgQueryURL = 'https://www.googleapis.com/customsearch/v1?key=AIzaSyCtY0Ysdb7hL1o3d2eIkNFKQfzh6vg9l08&cx=d83a0f4958be12349&searchType=image&imgSize=huge&q=';
      	  fetch(bgQueryURL + encodeURI(this.props.teamName) + '+wallpaper')
      	  .then(resp => resp.json())
    	    .then(json => {
    	      console.log('bg fetched', json);
    	      for (let item of json.items) {
          	  if (item.image.width > item.image.height) {
          	    console.log('got bg', item.link, document.body)
          	    document.body.style.backgroundImage = 'url(' + item.link + ')';
          	    break;
          	  }
    	      }
    	    });
        }
      }
      else {
        document.body.style.backgroundImage = 'none';
      }
    }
  }
  
  
  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('IGNORE error');
      return;
    }
    else if (event.error === 'aborted') {
      return;
    }
    this.setState({ listening: false, speechReady: false, autoRestart: false });
  }

  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();
  }

  async handleRawMessage(text) {
    //var text = "I think Tom Brady is great";
    const nlpStart = new Date().getTime();
    console.log('interim: ' + nlpStart, text);
    const output = hasUpperRegex.exec(text) || lookupRegex.exec(text);
    if (output) {
      //console.log('HAS UPPER2');
          
      const mentioned = output[output.length-1];
      if (lastMentionsInterim.indexOf(mentioned) === -1) {
        this.setState({interimMention: mentioned, infoOpen: true});
        lastMentionsInterim.push(mentioned);
        interimMentions[mentioned] = {promise: new Promise((resolve, reject) => {
          console.log('mentioned', mentioned, new Date().getTime(), output);
          
          for (let league in teamNames) {
            if (teamNames[league].hasOwnProperty(mentioned)) {
              teamNames[league][mentioned].league = league;
              const teamNameData = teamNames[league][mentioned];
              const team = teamData[teamNameData.sport][league][teamNameData.idx];
              team.sport = teamNameData.sport;
              team.league = teamNameData.league;
              resolve([team]);
              return;
            }
          }
          
          fetch('https://www.googleapis.com/customsearch/v1?key=AIzaSyCtY0Ysdb7hL1o3d2eIkNFKQfzh6vg9l08&cx=d452d0da4f98a9c81&q=' + encodeURI(mentioned) + '+stats',
          {headers: {"subject": this.props.subject}})
        	.then(resp => resp.json())
        	.then(json => {
        	  resolve(json.length ? json : null);
        	});
        })};
      }
    }
  }

  handleFormattedMessage(text) {
    console.log('final: ' + new Date().getTime(), text);
    const subject = this.props.subject;
    
    console.log('final check', interimMentions)
    
    const output = hasUpperRegex.exec(text) || lookupRegex.exec(text);
    if (output && Object.keys(interimMentions).length) {
      //console.log('HAS UPPER2');
          
      const mentioned = output[output.length-1];
      const interimMatch = interimMentions[mentioned];
      this.setState({infoOpen: false});
      
      interimMatch.promise.then((allAthletes) => {
        console.log('final match', mentioned, allAthletes, interimMatch.athletes);
        
        if (allAthletes) {
          this.props.resetAthlete();
          const athlete = allAthletes.shift();
          if (athlete.hasOwnProperty('location')) {
            this.props.showTeam(athlete);
          }
          else {
            this.props.fetchPlayer(athlete.id, athlete.sport, athlete.league);
          }
          this.props.setAlts(allAthletes.length ? allAthletes : null);
        }
      });
    }
    
    if (sportsTriggers.football.test(text) && subject !== 'football')
      this.props.changeSubject('football');
    else if (sportsTriggers.baseball.test(text) && subject !== 'baseball')
      this.props.changeSubject('baseball');
    else if (sportsTriggers.basketball.test(text) && subject !== 'basketball')
      this.props.changeSubject('basketball');
    
    if (text.indexOf('stop listening') !== -1) {
      this.reset();
    }
      
    interimMentions = {};
    lastMentionsInterim = []
  }

  handleError(err, extra) {
    console.error(err, extra);
    this.setState({ error: err.message || err });
  }
  
  handleCloseInfo(ev, reason) {
    if (reason !== 'clickaway')
      this.setState({infoOpen: false});
  }

  render() {
    const {
      listening, error, formattedMessages, speechReady
    } = this.state;
    
    const {
      hasAthlete, subject
    } = this.props;
    
    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 (hasAthlete)
      micWrapClass += ' move-to-bottom';

    return (
      <React.Fragment>
        <div className={micWrapClass}>
          <button type="button" className={micButtonClass} onClick={this.handleMicClick}>
            <ToggleIcon listening={listening} />
          </button>
        </div>
        
        <Snackbar open={this.state.infoOpen} autoHideDuration={1000} onClose={this.handleCloseInfo} style={{zIndex: 9999999999}}>
          <MuiAlert variant="outlined" severity="error" icon={false} style={{background: 'white'}}>
            {this.state.interimMention}
          </MuiAlert>
        </Snackbar>
      </React.Fragment>
    );
  }
};