const preact = require('preact');
const reactStringReplace = require('react-string-replace');

const specThresholds = require('./info.thresholds');
const { INFO } = require('./../constants');
const { convertItem, removeTier } = require('../utils');
const { tutorialStage } = require('../tutorial.utils');
const shapes = require('./shapes');


class InfoComponent extends preact.Component {
    shouldComponentUpdate(newProps, newState) {
        if (newProps.tutorial !== this.props.tutorial) return true;
        // We don't care about info during tutorial
        if (newProps.tutorial && this.props.instance.time_control === 'Practice'
            && this.props.instance.rounds.length === 1) return false;
        if (newProps.info !== this.props.info) return true;
        if (newState.comboItem !== this.state.comboItem) return true;

        return false;
    }

    componentDidUpdate(prevProps) {
        // Catch case where mouse events don't properly clear state and info changed
        if (prevProps.info !== this.props.info && this.state.comboItem) this.setState({ comboItem: null });
    }

    render(args) {
        const {
            // Variables that will change
            info,
            tutorial,

            // Static
            player, // Only used for colour calcs which will be update if info changes
            ws,
            itemInfo,
            instance, // Only used for instance id
            // functions
            setInfo,
            setTutorialNull,
        } = args;
        const { comboItem } = this.state;
        function Info() {
            if (tutorial) {
                const tutorialStageInfo = tutorialStage(tutorial, ws, setTutorialNull, instance);
                if (tutorialStageInfo) return tutorialStageInfo;
            }
            if (!info) return false;
            if (info.includes('constructName')) {
                return (
                    <div class='info-item'>
                        <h2> {info.replace('constructName ', '')} </h2>
                        <p> This is the name of your construct. <br />
                            Names are randomly generated and are purely cosmetic. <br />
                            You can change change your construct name in the <b>RESHAPE</b> tab outside of games.
                        </p>
                    </div>
                );
            }

            if (info.includes('constructAvatar')) {
                return (
                    <div class='info-item'>
                        <h2> {info.replace('constructAvatar ', '')} </h2>
                        <p> This is your construct avatar. <br />
                            Avatars are randomly generated and are purely cosmetic. <br />
                            You can change your construct avatar in the <b>RESHAPE</b> tab outside of games.
                        </p>
                    </div>
                );
            }
            const fullInfo = comboItem
                ? itemInfo.items.find(i => i.item === comboItem) || INFO[comboItem]
                : itemInfo.items.find(i => i.item === info) || INFO[info];
            if (!fullInfo) return false;
            const isSkill = fullInfo.skill;
            const isSpec = fullInfo.spec;

            const itemDescription = () => {
                const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat|LIFE|SPEED|POWER)/;
                const infoDescription = reactStringReplace(fullInfo.description, regEx, m => shapes[m]());
                return <div>{reactStringReplace(infoDescription, '\n', () => <br />)}</div>;
            };

            if (isSkill || isSpec) {
                let infoName = fullInfo.item;
                while (infoName.includes('Plus')) infoName = infoName.replace('Plus', '+');

                const itemSource = itemInfo.combos.filter(c => c.item === removeTier(fullInfo.item));
                
                let itemSourceInfo = itemSource.length && !isSpec
                    ? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
                    : false;

                let header = null;
                if (!itemSource.length) header = isSkill ? <h3> SKILL </h3> : <h3> SPEC </h3>;
                if (itemSourceInfo) {
                    while (itemSourceInfo.includes('Plus')) itemSourceInfo = itemSourceInfo.replace('Plus', '+');
                    const itemRegEx = /(Red|Blue|Green)/;
                    itemSourceInfo = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
                }

                const cooldown = isSkill && fullInfo.cooldown ? <div>{fullInfo.cooldown} Turn delay</div> : null;

                const speed =  isSkill
                    ? <div> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </div>
                    : null;

                const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null;

                return (
                    <div class={isSkill ? 'info-item' : 'info-item'}>
                        <h2>{infoName} {fullInfo.cost}b</h2>
                        {header}
                        {itemSourceInfo}
                        {cooldown}
                        {itemDescription()}
                        {speed}
                        {thresholds}
                    </div>
                );
            }
            const cost = fullInfo.cost ? `- ${fullInfo.cost}b` : false;
            return (
                <div class="info-item">
                    <h2>{fullInfo.item} {cost}</h2>
                    {itemDescription()}
                </div>
            );
        }

        const Combos = () => {
            if (tutorial && instance.time_control === 'Practice' && instance.rounds.length === 1) return false;
            const generalNotes = (
                <div class="combos">
                    <h2> General </h2>
                    <p>
                        You can preview combos by clicking the combined item when it appears in this section. <br />
                        Click the <b>READY</b> button to start the <b>GAME PHASE</b>.
                    </p>
                </div>
            );
            if (!player) return generalNotes;
            if (!info) return generalNotes;

            const vboxCombos = itemInfo.combos.filter(c => c.components.includes(info));
            if (vboxCombos.length > 6 || vboxCombos.length === 0) return generalNotes;

            return (
                <table class="combos">
                    <tbody>
                        {vboxCombos.map((c, i) =>
                            <tr key={i}>
                                <td class="table-button"
                                    onMouseOver={e => {
                                        e.stopPropagation();
                                        this.setState({ comboItem: c.item });
                                    }}
                                    onClick={() => setInfo(c.item)}
                                > {convertItem(c.item)} </td>

                                {c.components.map((u, j) => <td key={j} >{convertItem(u)}</td>)}
                            </tr>
                        )}
                    </tbody>
                </table>
            );
        };

        return (
            <div class='info' onMouseOver={() => this.setState({ comboItem: null })}>
                <Info />
                <Combos />
            </div>
        );
    }
}

module.exports = InfoComponent;
