import * as React from "react";
import {ChangeEvent, JSX} from "react";
import {PlayerAndScore} from "../../pkg/word_grid";
import {
    CellType,
    cellTypeToDetails,
    CoordinateData,
    GridArrowData,
    GridArrowDispatch,
    GridArrowDispatchActionType,
    HighlightableLetterData,
    LocationType,
    PlayableLetterData,
    TileDispatch,
    TileDispatchActionType,
} from "./utils";


export function TileSlot(props: {
        tile?: React.JSX.Element | undefined,
        location: CoordinateData,
        tileDispatch: TileDispatch,
        arrowDispatch?: GridArrowDispatch,
}): React.JSX.Element {
    let isDraggable = props.tile !== undefined;

    function onDragStart(e: React.DragEvent<HTMLDivElement>) {
        e.dataTransfer.effectAllowed = "move";
        e.dataTransfer.setData("wordGrid/coords", JSON.stringify(props.location));
    }

    function onDrop(e: React.DragEvent<HTMLDivElement>) {
        const startLocation: CoordinateData = JSON.parse(e.dataTransfer.getData("wordGrid/coords"));
        const thisLocation = props.location;

        props.tileDispatch({action: TileDispatchActionType.MOVE, start: startLocation, end: thisLocation});
    }

    let className = "tileSpot";
    if (props.location.location === LocationType.GRID) {
        className += " ephemeral";
    }

    let onClick: () => void;
    if(props.arrowDispatch != null && props.location.location == LocationType.GRID) {
        onClick = () => {
            props.arrowDispatch({action: GridArrowDispatchActionType.CYCLE, position: props.location.index});
        }
    } else if(props.location.location == LocationType.TRAY && props.tile != null && props.tile.props.data.text != ' ' && props.tile.props.data.text != '') {
        onClick = () => {
            props.tileDispatch({
                action: TileDispatchActionType.MOVE_TO_ARROW, end: undefined, start: props.location,
            });
        }
    }

    return <div className={className}
        draggable={isDraggable}
        onDragStart={onDragStart}
        onDrop={onDrop}
        onClick={onClick}
        onDragOver={(e) => {e.preventDefault()}}
    >
        {props.tile}
    </div>

}

export function Letter(props: { data: HighlightableLetterData, letterUpdater?: (value: string) => void }): React.JSX.Element {

    function modifyThisLetter(value:string){
        props.letterUpdater(value);
    }


    function onBlankInput(e: ChangeEvent<HTMLInputElement>){
        let value = e.target.value.toUpperCase();
        if(value.length > 1){
            value = value[value.length - 1];
        } else if(value.length == 0){
            modifyThisLetter(value);
            return;
        }

        // Now check that it's a letter
        let is_letter = value.match("[A-Z]") != null;
        if(is_letter){
            modifyThisLetter(value);
        } else {
            // Cancel and do nothing
            e.preventDefault();
        }

    }

    if(props.data.is_blank && props.data.ephemeral) {
        return <div className="letter">
            <input className="blank-input" type="text" onChange={onBlankInput} value={props.data.text} />
            <div className="letter-points">{props.data.points}</div>
        </div>
    } else {
        let className = "text";
        if (props.data.is_blank) { // not ephemeral
            className += " prev-blank";
        }
        let letterClassName = "letter";
        if (props.data.highlight) {
            letterClassName += " highlight";
        }
        return <div className={letterClassName}>
            <div className={className}>{props.data.text}</div>
            <div className="letter-points">{props.data.points}</div>
        </div>
    }



}

export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength: number, trayDispatch: TileDispatch }): React.JSX.Element {

    let elements: JSX.Element[] = [];
    for (let i=0; i<props.trayLength; i++) {
        elements.push(
            <TileSlot
                key={"empty" + i}
                location={{location: LocationType.TRAY, index: i}}
                tileDispatch={props.trayDispatch} />
        );
    }

    props.letters
        .filter((x) => {return x !== undefined;})
        .forEach((letter, i) => {
        if (letter.location === LocationType.TRAY) {
            elements[letter.index] =
                <TileSlot
                    tile={<Letter
                        data={{...letter, highlight: false}}
                        letterUpdater={(value) => {
                            props.trayDispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value})
                        }}
                    />}
                    key={"letter_tray" + letter.index}
                    location={{location: LocationType.TRAY, index: letter.index}}
                    tileDispatch={props.trayDispatch} />

        }
    });

    return (
        <div className="tray">
            {elements}
        </div>
    )

}

export function Arrow(props: {
    data: GridArrowData,
    dispatch: GridArrowDispatch,
}) {

    return <div
        className={`arrow ${props.data.direction}`}
    >
        ➡
    </div>;

}

export function Grid(props: {
        cellTypes: CellType[],
        playerLetters: Array<PlayableLetterData>,
        boardLetters: HighlightableLetterData[],
        tileDispatch: TileDispatch,
        arrow: GridArrowData,
        arrowDispatch: GridArrowDispatch,
}) {

    const elements = props.cellTypes.map((ct, i) => {
        const {className, text} = cellTypeToDetails(ct);

        let tileElement: JSX.Element;
        if (props.boardLetters[i] !== undefined) {
            tileElement = <Letter data={props.boardLetters[i]} />;
        } else {
            tileElement = <>
                <span>{text}</span>
                <TileSlot
                    location={{location: LocationType.GRID, index: i}}
                    tileDispatch={props.tileDispatch}
                    arrowDispatch={props.arrowDispatch}
                />

            </>;
        }

        let arrowElement: JSX.Element;
        if(props.arrow != null && props.arrow.position == i) {
            arrowElement = <Arrow data={props.arrow} dispatch={props.arrowDispatch} />;
        }

        return <div key={i} className={"grid-spot " + className}>
            {tileElement}
            {arrowElement}
        </div>;
    });

    props.playerLetters
        .filter((letter) => {return letter !== undefined})
        .forEach((letter, i) => {
        if (letter.location === LocationType.GRID) {
            const ct = props.cellTypes[letter.index];
            const {className} = cellTypeToDetails(ct);

            elements[letter.index] =
                <div key={"letter" + letter.index} className={"grid-spot " + className}>
                    <TileSlot
                        tile={<Letter
                            data={{...letter, highlight: false}}
                            letterUpdater={(value) => {
                                props.tileDispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value});
                            }}
                        />}
                        location={{location: LocationType.GRID, index: letter.index}}
                        tileDispatch={props.tileDispatch} />
                </div>;


        }
    });

    return <div className="board-grid">
        {elements}
    </div>
}

export function Scores(props: {playerScores: Array<PlayerAndScore>}){
    let elements = props.playerScores.map((ps) => {
        return <div key={ps.name}>
            <h3>{ps.name}</h3>
            <span>{ps.score}</span>
        </div>;
    });

    return <div className="scoring">
        {elements}
    </div>
}
