import {
  AppBar,
  IconButton,
  Paper,
  Toolbar,
  Tooltip,
  Typography,
} from '@material-ui/core';
import ToggleOffIcon from '@material-ui/icons/ToggleOff';
import ToggleOnIcon from '@material-ui/icons/ToggleOn';
import Skill from 'components/Skill';
import EffectIcon from 'components/Skill/EffectIcon';
import { equals } from 'ramda';
import React, { PureComponent } from 'react';
import { array } from 'react-proptypes';
import { connect } from 'react-redux';
import { sortBy } from 'utils/array';
import {
  deepCopy,
  objectHasProperties,
} from 'utils/object';
import { substituteVars } from 'utils/skills';

class SkillCombos extends PureComponent {
  static propTypes = {
    skillsetData: array.isRequired,
  };

  state = {
    showAll: true,
  };

  componentWillUpdate(nextProps, nextState, nextContext) {
    return (!equals(this.props, nextProps) || !equals(this.state, nextState));
  }

  toggleVisibility = () => {
    const { showAll } = this.state;
    this.setState({ showAll: !showAll });
  };

  createComboRow = (combo, sub) => {
    const { skill, effect, activator, applies, combos } = combo;
    let nodes = [];
    // starting skill
    if (!sub) {
      nodes.push(
        <div className="combo-skill" key={`sk-${Math.random()}`}>
          <Skill
            id={skill.id}
            learned={skill.isLearned}
            noRequirement
            remainingPoints={0}
          />
          <EffectIcon
            {...effect}
            tooltip={`<span class="text-orange">${skill.name}</span> applies <span class="${effect.negative
              ? 'tt-debuff' : 'tt-buff'}">${effect.name}</span>`}
          />
        </div>,
      );
      nodes.push(<div className="combo-arrow" key={`ca2-${Math.random()}`} />);
    }

    // comboing skill
    const comboText = `<span class="text-orange">${activator.name}:</span> ${substituteVars(applies.text, skill.vars)}`;
    nodes.push(
      <div className="combo-skill" key={`skc-${Math.random()}`}>
        <Skill
          learned={activator.isLearned}
          noRequirement
          remainingPoints={0}
          {...activator}
        />
        {applies.applies ?
          <EffectIcon
            {...applies.applies}
            tooltip={comboText}
          /> :
          <Tooltip title={<div dangerouslySetInnerHTML={{ __html: comboText }} />}>
            <div className="combo-icon" />
          </Tooltip>
        }
      </div>,
    );
    if (combos && combos.length > 0) {
      nodes.push(<div key={`ca-${Math.random()}`} className="combo-arrow" />);
      if (combos.length > 1) {
        nodes = nodes.concat(
          <div className="combo-col" key={`cc-${Math.random()}`}>
            {combos.map((combo, index) =>
              <div
                className="combo-row"
                key={`c-${Math.random()}-${index}`}
              >
                {this.createComboRow(combo, true)}
              </div>,
            )}
          </div>,
        );
      } else {
        nodes = nodes.concat(this.createComboRow(combos[0], true));
      }
    }

    return nodes;
  };

  findComboSkills = (effect) => {
    const skills = [];
    this.comboSkills.forEach(comboSkill => {
      const skillCombos = comboSkill.combos.filter(combo => equals(combo.effect, effect));
      if (skillCombos.length > 0) {
        skills.push({ skill: comboSkill, combos: skillCombos });
      }
    });
    return skills;
  };

  createCombosForEffects = (skill, effects, notSkills) => {
    const combos = [];
    // add this skill to the list of subcombos to skip
    notSkills = deepCopy(notSkills);
    notSkills.push(skill.id);
    effects.forEach(effect => {
      // look for combos on this effect
      this.findComboSkills(effect).forEach(comboSkill_ => {
        const { skill: comboSkill, combos: skillCombos } = comboSkill_;
        if (notSkills.includes(comboSkill.id)) return;
        const causeEffects = skillCombos.filter(combo => combo.applies);
        const subCombos = causeEffects.length > 0
          ? this.createCombosForEffects(comboSkill, causeEffects.map(combo => combo.applies), notSkills) : null;
        skillCombos.forEach(comboEffect => {
          this.combos.push({
            skill,
            effect,
            activator: comboSkill,
            applies: comboEffect,
            combos: subCombos,
          });
        });
      });
    });
    return combos;
  };

  combos = [];
  comboSkills = [];
  comboActivators = [];

  render() {
    const { skillsetData, skillsets, skills: skillData } = this.props;
    const { showAll } = this.state;
    this.combos = [];
    this.comboSkills = [];
    this.comboActivators = [];

    skillsetData.forEach(skillTree => {
      const { id: skillsetId, skills, ancestrals } = skillTree;
      if (skillsetId === null || !objectHasProperties(skillsets)) return;
      const skillset = skillsets[skillsetId];
      let skillList = skillset.skills.map(s => deepCopy(skillData[s])).filter(s => Boolean(s));
      if (skillList.length === 0) return;
      // skillset.ancestrals.forEach((ancestral, ancestralId) => {
      //   const selected = ancestrals[ancestralId];
      //   if (selected === 1 || selected === 2) {
      //     skillList[ancestral.skillId] = {
      //       ...skillList[ancestral.skillId],
      //       ...ancestral.variants[selected - 1],
      //     };
      //   }
      // });
      // embed skill data
      skillList.forEach((skill, skillId) => {
        skill.isLearned = skills[skillId] === 1;
      });

      if (!showAll) {
        skillList = skillList.filter(s => s.isLearned);
      }

      this.comboSkills = this.comboSkills.concat(skillList.filter(skill => skill.combos && skill.combos.length > 0));
      this.comboActivators = this.comboActivators.concat(skillList.filter(skill => skill && skill.effects && skill.effects.length > 0));
    });

    // loop through all activators
    this.comboActivators.forEach(skill => {
      this.combos = this.combos.concat(this.createCombosForEffects(skill, skill.effects, []));
    });

    this.combos = this.combos.sort(sortBy('name'));

    return (
      <Paper className="skill-combos section">
        <AppBar position="static">
          <Toolbar variant="dense">
            <Typography variant="subtitle1" className="title-text">{showAll ? 'Available'
              : 'Learned'} Combos ({this.combos.length})</Typography>
            <Tooltip title={`Show ${showAll ? 'Only Learned' : 'All Available'} Combos`}>
              <IconButton color="inherit" aria-label="Toggle Visibility" onClick={this.toggleVisibility}>
                {showAll ? <ToggleOffIcon /> : <ToggleOnIcon />}
              </IconButton>
            </Tooltip>
          </Toolbar>
        </AppBar>
        <div className="combos-list">
          {this.combos.length === 0 &&
          <Typography>You have no {showAll ? 'available' : 'learned'} combos.</Typography>}
          {this.combos.map((combo, index) =>
            <div className="combo-row" key={`c-${index}`}>
              {this.createComboRow(combo)}
            </div>,
          )}
        </div>
      </Paper>
    );
  }
}

const mapStateToProps = ({ gameData: { skillsets, skills } }) => ({
  skillsets,
  skills,
});

export default connect(mapStateToProps, null)(SkillCombos);