import React, { Component, Fragment } from 'react';
import CircularProgress from '@material-ui/core/CircularProgress';

const _ = require('lodash')

//import { makeStyles } from '@material-ui/core/styles';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import InputLabel from '@material-ui/core/InputLabel';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import setVal from '../utils/set-val';
import getFilterQSs from '../utils/get-filter-qss';

import { Chart } from "react-google-charts";

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

const theme = createMuiTheme({
  overrides: {
    MuiSelect: {
      select: {
        "&:focus": {
          backgroundColor: '#ffffff'
        }
      }
    }
  }
});

const selectStyle = {background: 'white'},
      formControlStyle ={marginTop: 6, marginBottom: 12},
      titleCaseRegex = /\w\S*/g,
      titleCaseReplacer = (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();

export class ChartPanel extends Component {
  constructor(props) {
    super();
    this.state = {
      stats: null,
      splits: null,
      selects: {
        stats: [
          //{label: 'game-by-game', title: 'Season, By Game'},
          {label: 'yoy-totals', title: 'YoY Totals'},
          //{label: 'by-opp-team', title: 'Per Game, By Team'}
        ],
        splits: [
          {label: 'game-by-game', title: 'Season, By Game'},
          //{label: 'by-opp-team', title: 'Per Game, By Team'}
        ]
      },
      selectType: 'stats',
      selectCat: '',
      selectSubCat: '',
      select1: '',
      data: null
    };
    
    this.changeSelectType = this.changeSelectType.bind(this);
    this.changeSelectCat = this.changeSelectCat.bind(this);
    this.changeSplit = this.changeSplit.bind(this);
    this.changeSelectSubCat = this.changeSelectSubCat.bind(this);
    this.changeSelect1 = this.changeSelect1.bind(this);
    this.changeFilter = this.changeFilter.bind(this);
    this.filterMap = this.filterMap.bind(this);
    this.getFetchURL = this.getFetchURL.bind(this);
    this.getFilterOpts = this.getFilterOpts.bind(this);
    this.fetchSchedule = this.fetchSchedule.bind(this);
    this.toggleCollegeID = this.toggleCollegeID.bind(this);
  }
  
  componentDidMount() {
    const props = this.props;
    this.state.league = props.league;
    this.state.aid = props.id;
    this.fetchStats().then(this.fetchSplits().then(this.fetchSchedule));
    theme.overrides.MuiSelect.select['&:focus'].borderColor = '#' + props.team.color;
  }
  
  componentDidUpdate(prevProps) {
    const props = this.props;
    
    if (props.sport !== prevProps.sport || props.league !== prevProps.league || props.id !== prevProps.id) {
      this.state.league = props.league;
      this.state.aid = props.id;
      this.fetchStats().then(this.fetchSplits().then(this.fetchSchedule));
      theme.overrides.MuiSelect.select['&:focus'].borderColor = '#' + props.team.color;
    }
  }
  
  fetchSchedule() {
    const {props, state} = this;
    fetch('https://site.web.api.espn.com/apis/site/v2/sports/' + props.sport + '/' + state.league + '/teams/' + props.team.abbreviation + '/schedule',
    {headers: {"athleteID": state.aid}});
  }
  
  fetchStats(url, switchedToCollege=false) {
    const {props, state} = this;
          
    let otherLeagues = [];
    if (!url)
      url = this.getFetchURL('stats');
    else if (switchedToCollege) {
      for (let filter of state.stats.filters) {
        if (filter.name === 'league') {
          otherLeagues = filter.options.filter(option => (!option.value.includes('college')));
          break;
        }
      }
    }
    
    console.log('fetchstat', url)
    
    return fetch(url)
    .then(resp => resp.json())
    .then(json => {
      const { categories } = json;
      
      if (switchedToCollege) {
        console.log('switched to college, wait', json.filters);
        for (let filter of json.filters) {
          if (filter.name === 'league') {
            console.log('league opts', filter.options, otherLeagues);
            filter.options = filter.options.concat(otherLeagues);
            break;
          }
        }
      }
      
      console.log('transformed opts 1', json.filters);

      json.filterValues = {};
      json.filters = json.filters.filter((filter) => {
        if (filter.name === 'league' && props.collegeAID) {
          if (!filter.options.find(option => (option.value.includes('college')))) {
            filter.useCollegeId = true
            filter.options.push({value: 'college-' + props.sport, displayValue: 'NCAA'});
          }
        }
        
        if (filter.options.length > 1) {
          json.filterValues[filter.name] = filter.value;
          return true;
        }
      });
      
      console.log('transformed opts 2', json.filters);
      
      const isBaseball = (props.sport === 'baseball'),
            leagueTeamData = teamData[props.sport][state.league],
            hasTeamData = !!leagueTeamData;
      let statTeamData = {};
      
      for (let stat of categories[0].statistics) {
        if (!!stat.season && !statTeamData.hasOwnProperty(stat.season.year))
          statTeamData[stat.season.year] = (hasTeamData && leagueTeamData[stat.teamId]) ? stat.teamId : stat.teamSlug;
      }
      
      for (let category of categories) {
        if (isBaseball) {
          let str = category.displayName.toLowerCase().split('-');
          for (let i in str) {
            str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1);
          }
          category.displayName = str.join(' ');
        }
      }
      
      if (state.selectType === 'stats') {
        this.updateChart({
          stats: json,
          selectCat: '0',
          selectSubCat: '0',
          select1: state.selects.stats[0].label,
          statTeamData
        });
      }
      else
        this.setState({stats: json, statTeamData});
    })
    .catch((err) => {
      console.error('caught queue', err);
    })
  }
  
  getFetchURL(type) {
    const sport = this.props.sport,
          state = this.state;
    return 'https://site.web.api.espn.com/apis/common/v3/sports/' + sport + '/' + (sport === 'soccer' ? '' : state.league + '/') + 'athletes/' + state.aid + '/' + type;
  }
  
  fetchSplits(url) {
    const {props, state} = this;
          
    if (!url)
      url = this.getFetchURL('splits');
    
    return fetch(url)
    .then(resp => resp.json())
    .then(json => {
      json.filterValues = {};
      json.filters = json.filters.filter((filter) => {
        if (filter.options.length > 1 && filter.name !== 'league') {
          json.filterValues[filter.name] = filter.value
          return true;
        }
      });
            
      for (let cat of json.splitCategories) {
        cat.displayName = cat.displayName.replace(titleCaseRegex, titleCaseReplacer);
      }
      
      if (this.state.selectType === 'splits')
          this.updateChart({ splits: json });
      else
        this.setState({splits: json});
        //this.state.splits = json;
        
    });
  }
  
  changeSelectType(ev) {
    this.updateChart({selectType: ev.target.value, selectCat: 0, selectSubCat: 0});
  }
  
  changeSelectCat(ev) {
    console.log('changeCat', ev.target.selectedIndex, ev.target);
    this.updateChart({selectCat: ev.target.selectedIndex, selectSubCat: 0});
  }
  
  changeSelectSubCat(ev) {
    this.updateChart({selectSubCat: ev.target.selectedIndex});
  }
  
  changeSelect1(ev) {
    this.updateChart({select1: ev.target.value});
  }
  
  toggleCollegeID(shouldUse, league) {
    const { props, state } = this;
    const willUse = state.stats.filters.find(filter => (filter.name === 'league' && filter.hasOwnProperty('useCollegeId')));
    
    if ((shouldUse && state.aid !== props.collegeAID && willUse) || (!shouldUse && state.aid !== props.id && !willUse)) {
      this.state.league = league;
      this.state.aid = (league.includes('college')) ? props.collegeAID : props.id;
    }
  }
  
  changeFilter(ev) {
    const type = this.state.selectType,
          filterName = ev.target.id.replace('select-filter-', ''),
          filterVal = ev.target.value;
    
    console.log('changeFilter', filterName, filterVal);
    
    let filters = {};
    this.state[type].filters.map((filter) => {
      filters[filter.name] = filter.value;
    });
    
    filters[filterName] = filterVal;
    
    const qs = new URLSearchParams(filters).toString();
    const changedLeague = (filterName === 'league');
    let switchToCollege = false;
    
    if (changedLeague) {
      switchToCollege = filterVal.includes('college');
      if (type === 'stats') {
        //this.toggleCollegeID(true, filterVal);
        //const useCollegeId = this.state.stats.filters.find(filter => (filter.name === 'league' && filter.hasOwnProperty('useCollegeId')));
        //console.log('changedleague', useCollegeId, )
        
        
        this.state.league = filterVal;
        this.state.aid = (switchToCollege) ? this.props.collegeAID : this.props.id;
      }
    }
    console.log('fetching', switchToCollege)
    this.fetchStats(this.getFetchURL('stats') + ((switchToCollege) ? '' : '?' + qs), switchToCollege);
    this.fetchSplits(this.getFetchURL('splits') + '?' + qs, true);
  }
  
  changeSplit(ev) {
    console.log('changeSplit', ev.target.selectedIndex, ev.target, ev);
  }
  
  updateChart(newStateData) {
    const {props, state} = this,
          metricGroup = newStateData.select1 || state.select1,
          catIdx = newStateData.hasOwnProperty('selectCat') ? newStateData.selectCat : state.selectCat,
          statIdx = newStateData.hasOwnProperty('selectSubCat') ? newStateData.selectSubCat : state.selectSubCat,
          type = newStateData.selectType || state.selectType,
          src = newStateData[type] || state[type],
          strokeWidth = (props.winWidth < 400) ? '2' : '3';
          
    console.log('update', metricGroup, catIdx, statIdx, type, src, newStateData);
    
    let data = [], statCat, isStacked;
    const leagueTeamData = teamData[props.sport][state.league];
    
    if (type === 'stats') {
      if (metricGroup === 'yoy-totals') {}
      
      statCat = src.categories[catIdx];
      isStacked = (statCat.displayNames[statIdx].indexOf('Made-Attempted') !== -1);
    
      const statCt = statCat.statistics.length;
        
      newStateData.barWidth = (statCt === 1) ? '25%' : (statCt === 2) ? '33%' : (statCt === 3) ? '41%' : (statCt === 4) ? '50%' : '61.8%';
      newStateData.isStacked = isStacked;
      
      if (isStacked) {
        newStateData.series = [ {color:'#c8102e'}, {color:'#1d428a'} ];
        data.push([
          'Season',
          statCat.displayNames[statIdx].replace('Made-Attempted', 'Made'),
          statCat.displayNames[statIdx].replace('Made-Attempted', 'Attempted')
        ]);
      }
      else {
        newStateData.series = null;
        data.push([
          'Season',
          statCat.displayNames[statIdx],
          { role: 'style' },
          { 'type': 'string', 'role': 'tooltip', 'p': {'html': true} },
          {type: 'string', role: 'annotation'}
        ]);
      }
      for (let yearData of statCat.statistics) {
        let team = (!!leagueTeamData && leagueTeamData[yearData.teamId]) || src.teams[yearData.teamSlug];
        console.log('team', team, yearData, teamData)
        if (isStacked) {
          const statArr = yearData.stats[statIdx].split('-');
          const made = parseFloat(statArr[0]);
          data.push([
            yearData.season.displayName,
            made,
            (parseFloat(statArr[1]) - made),
          ]);
        }
        else {
          const stat = parseFloat(yearData.stats[statIdx].replace(',', ''));
          data.push([
            yearData.season.displayName,
            stat,
            'stroke-color: #' + team.alternateColor + '; stroke-width: ' + strokeWidth + '; color: #' + team.color,
            '<div style="width:160px; padding:16px;">' +
              '<img style="width:80px; height:80px; display: block; margin:0 auto;" src="https://a.espncdn.com/combiner/i?img=/i/teamlogos/' + state.league + '/500/' + team.abbreviation + '.png&w=250&h=250">' +
              '<br>' +
              '<div style="text-align:center; font-weight:bold">' + team.displayName+ '</div>' +
              '<br><br>' +
              '<b>' + yearData.season.displayName + '</b>' +
              '<br><br>' +
              '<span>' + statCat.displayNames[statIdx] + ': <b>' + stat + '</b></span>' +
            '</div>',
            team.abbreviation
          ]);
        }
      }
    }
    else if (type === 'splits') {
      console.log('issplit');
      if (metricGroup === 'game-by-game') { }
      else if (metricGroup === 'by-opp-team') { }
      
      const displayNames = src.displayNames;
      statCat = src.splitCategories[catIdx];
      isStacked = (displayNames[statIdx].indexOf('Made-Attempted') !== -1);
      const stats = newStateData.stats || state.stats;
      
      console.log(displayNames, statCat, isStacked, stats);
      
      if (isStacked) {
        newStateData.series = [ {color:'#c8102e'}, {color:'#1d428a'} ];
        data.push([
          'Season',
          statCat.displayNames[statIdx].replace('Made-Attempted', 'Made'),
          statCat.displayNames[statIdx].replace('Made-Attempted', 'Attempted')
        ]);
      }
      else {
        newStateData.series = null;
        data.push([
          'Season',
          displayNames[statIdx],
          { role: 'style' },
          { 'type': 'string', 'role': 'tooltip', 'p': {'html': true} },
          {type: 'string', role: 'annotation'}
        ]);
      }
      
      const teamRef = state.statTeamData[src.filterValues.season];
      const team = (!!leagueTeamData && leagueTeamData[teamRef]) || stats.teams[teamRef];
      
      console.log(teamRef, team, statCat.splits)
      
      for (let rowData of statCat.splits) {
        console.log('team', rowData, teamRef, team)
        if (isStacked) {
          const statArr = rowData.stats[statIdx].split('-');
          const made = parseFloat(statArr[0]);
          data.push([
            rowData.season.displayName,
            made,
            (parseFloat(statArr[1]) - made),
          ]);
        }
        else {
          const stat = parseFloat(rowData.stats[statIdx].replace(',', ''));
          data.push([
            rowData.displayName,
            stat,
            'stroke-color: #' + team.alternateColor + '; stroke-width: ' + strokeWidth + '; color: #' + team.color,
            '<div style="width:160px; padding:16px;">' +
              '<img style="width:80px; height:80px; display: block; margin:0 auto;" src="https://a.espncdn.com/combiner/i?img=/i/teamlogos/' + state.league + '/500/' + team.abbreviation + '.png&w=250&h=250">' +
              '<br>' +
              '<div style="text-align:center; font-weight:bold">' + team.displayName+ '</div>' +
              '<br><br>' +
              '<b>' + rowData.displayName + '</b>' +
              '<br><br>' +
              '<span>' + displayNames[statIdx] + ': <b>' + stat + '</b></span>' +
            '</div>',
            team.abbreviation
          ]);
        }
      }
    }
    newStateData.data = data;
    console.log('chart new state', newStateData);
    this.setState(newStateData);
  }
  
  getFilterOpts(opt, i) {
    return (
      <option key={i} value={opt.value}>{opt.displayValue}</option>
    );
  }
  
  filterMap(filter, fi) {
    return this.buildSelect(fi,
      'select-filter-' + filter.name,
      filter.displayName,
      this.changeFilter,
      filter.options.map(this.getFilterOpts),
      this.state[this.state.selectType].filterValues[filter.name]
    );
  }
  
  buildSelect(key, id, label, onChange, opts, value) {
    const props = (value) ? {defaultValue: value} : {};
    return (
      <FormControl key={key} variant="outlined" style={formControlStyle}>
        <InputLabel htmlFor={id}>{label}</InputLabel>
        <Select
          native
          onChange={onChange}
          style={selectStyle}
          label={label}
          {...props}
          inputProps={{
            name: label,
            id: id,
          }}
        >{opts}</Select>
      </FormControl>
    );
  }
  
  render() {
    const stats = this.props.stats,
          state = this.state,
          selectType = state.selectType,
          winWidth = this.props.winWidth,
          selects = state.selects[selectType];
          
    console.log('RENDER', state, this.props, theme);
    
    const selectedType = state[selectType];
    //const selectedCats = selectedType ? _.get(state[selectType].categories, selectedType.filters.reduce((acc, {name, value}) => (acc + ((acc) ? '.' : '') + name + '.' + value), '')) : null;
    
    let selectCatOpts, selectSubCatOpts, select1Opts, selectSubCatLabel, filterSelects, splitOpts, filterOpts, leagueOpts;
    
    if (!!selectedType) {
      console.log('selectedType', selectedType);
      const cats = (selectType === 'stats') ? selectedType.categories : selectedType.splitCategories;
      selectCatOpts = cats.map((cat, i) =>
        <option key={i} value={cat.name}>{cat.displayName}</option>
      );
      
      const selectCat = cats[state.selectCat];
      filterSelects = selectedType.filters.map(this.filterMap);
      
      console.log('test', state.splits && state.splits.splitCategories[0].hasOwnProperty('splits'), state.splits && state.splits.splitCategories[0])
      
      const selectTypes = [{name: 'stats', title: 'Stats'}];
      if (state.splits && state.splits.splitCategories[0].hasOwnProperty('splits'))
        selectTypes.push({name: 'splits', title: 'Splits'});
        
      const selectTypeOpts = selectTypes.map((item, i) =>
        <option key={i} value={item.name}>{item.title}</option>
      );
        
      if (selectType === 'stats') {
        selectSubCatLabel = 'Stat';
        
        selectSubCatOpts = (selectCat) ? selectCat.displayNames.map((item, i) =>
          <option key={i} value={selectCat.names[i]}>{item}</option>
        ) : null;
        
        select1Opts = (selects.length > 1) ? state.selects[selectType].map((item, i) =>
          <option key={i} value={item.label}>{item.title}</option>
        ) : null;
      }
      else {
        selectSubCatLabel = 'Split';
        
        selectSubCatOpts = (selectCat) ? selectedType.displayNames.map((item, i) =>
          <option key={i} value={selectedType.names[i]}>{item}</option>
        ) : null;
        
        splitOpts = (selectCat) ? selectCat.splits.map((item, i) =>
          <option key={i} value={item.abbreviation}>{item.displayName}</option>
        ) : null;
        
        delete this.currFilterVal;
      }
  
      console.log('filterSelects', filterSelects);
      
      return (
        <ThemeProvider theme={theme}>
          <div style={{maxWidth: 1260, margin: '0 auto'}}>
            <div style={{display: 'flex', flexWrap: 'wrap', justifyContent: 'space-evenly', padding: '6px 24px 6px 24px'}}>
              { this.buildSelect(10, 'select-type', 'Type', this.changeSelectType, selectTypeOpts) }
              
              { selectType === 'splits' &&
                <Fragment>
                  { select1Opts && this.buildSelect(11, 'select-1', 'Metric', this.changeSelect1, select1Opts) }
                </Fragment>
              }
              
              {filterSelects}
              
              { selectCatOpts && this.buildSelect(12, 'select-cat', 'Category', this.changeSelectCat, selectCatOpts) }
              
              {(winWidth < 768) && <br/>}
              
              { selectSubCatOpts && this.buildSelect(13, 'select-subcat', selectSubCatLabel, this.changeSelectSubCat, selectSubCatOpts) }
              
              
              { selectType === 'stats' && select1Opts && this.buildSelect(14, 'select-1', 'Metric', this.changeSelect1, select1Opts) }
            </div>
            
            { state.data && state.data.length &&
              <div style={{margin: 12, overflow: 'hidden', borderRadius: 10, border: '1px solid #cbccce'}}>
                <Chart
                  chartType="ColumnChart"
                  loader={
                    <div style={{position: 'relative', height: (winWidth < 400) ? 280 : 350}}>
                      <CircularProgress style={{position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)'}}/>
                    </div>
                  }
                  data={state.data}
                  options={{
                    animation: {
                      duration: 500,
                      easing: 'out',
                      startup: true,
                    },
                    annotations: {
                      textStyle: {
                        fontSize: 11,
                        bold: true,
                        //auraColor: '#ff0000' // The color of the text outline.
                      }
                    },
                    chart: {
                      title: 'Company Performance',
                      subtitle: 'Sales, Expenses, and Profit: 2014-2017',
                    },
                    chartArea: {
                      width: '80%',
                      height: (winWidth < 1024) ? '70%' : '60%',
                      left: (winWidth < 1024) ? '12%' : '9%',
                      top: (winWidth < 1024) ? '11%' : '16%'
                    },
                    bar: {groupWidth: state.barWidth},
                    height: (winWidth < 400) ? 280 : 350,
                    isStacked: state.isStacked,
                    legend: 'none',
                    series: state.series,
                    tooltip: { isHtml: true }
                  }}
                  // For tests
                  rootProps={{ 'data-testid': '1' }}
                />
              </div>
            }
          </div>
        </ThemeProvider>
      );
    }
    else {
      return null;
    }
  }
}

export default ChartPanel;