import { range } from "@common/utils";
import { useMemo, useState } from "preact/hooks";

interface Turn {
    isBlind: boolean;
    request: number | '-' | undefined;
    taken: number | '-' | undefined;
}

type RowType = number | 'Т' | 'Б' | 'З';
type Row = Turn[];

const numCards = 54;

export const App = () => {
    const [numPlayers, setNumPlayers] = useState(4);
    const [players, setPlayers] = useState<string[]>([]);
    const [rows, setRows] = useState<Row[]>([]);

    const rowTypes = useMemo(() => {
        const maxDeal = Math.floor(numCards / numPlayers);

        let rowTypes: RowType[] = [];
        for (let i = 1; i < maxDeal; i++) {
            rowTypes.push(i);
        }
        for (let p = 0; p < numPlayers; p++) {
            rowTypes.push(maxDeal);
        }
        rowTypes.push('Т');
        rowTypes.push('Б');
        rowTypes.push('З');
        return rowTypes;
    }, [numPlayers]);

    const mismatches: string[] = useMemo(() => {
        let mismatches: number[] = [];
        for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
            const row = rows[rowIndex];
            if (!row) continue;
            const type = rowTypes[rowIndex];
            let maxCount: number;
            if (typeof type === 'number') {
                maxCount = type;
            } else {
                maxCount = Math.floor(numCards / numPlayers);
            }
            let sum = 0;
            for (let player = 0; player < numPlayers; player++) {
                const turn = row[player];
                if (!turn) continue;

                let { request } = turn;
                if (typeof request !== 'number') {
                    request = 0;
                }
                sum += request;
            }
            mismatches[rowIndex] = maxCount - sum;
        }

        return mismatches.map(m => {
            if (m === 0) return '';
            if (m < 0) return '' + m;
            return '+' + m;
        });
    }, [rows, numPlayers]);

    const points: number[][] = useMemo(() => {
        const points: number[][] = [];

        for (let player = 0; player < numPlayers; player++) {
            for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
                const row = rows[rowIndex];
                if (!row) continue;
                const type = rowTypes[rowIndex];
                const turn = row[player];
                if (!turn) continue;

                let { request, taken, isBlind } = turn;
                if (request === '-') {
                    request = 0;
                }
                if (taken === '-') {
                    taken = 0;
                }
                if (typeof request !== 'number' || typeof taken !== 'number') {
                    continue;
                }
                let score = 0;
                const diff = taken - request;
                if (taken < request) {
                    score += diff * 10;
                } else if (taken > request) {
                    score += taken;
                } else if (taken === 0 && request === 0) {
                    score += 5;
                } else if (taken === request) {
                    score += 10 * taken;
                }

                if (isBlind) {
                    score *= 2;
                }
                if (type === 'З') {
                    score *= 2;
                }

                let pointsRow = points[rowIndex];
                let prevScore = points[rowIndex - 1]?.[player] ?? 0;
                if (!pointsRow) {
                    pointsRow = [];
                }
                pointsRow[player] = prevScore + score;
                points[rowIndex] = pointsRow;
            }
        }

        return points;
    }, [rows, rowTypes, numPlayers]);

    const handleSetPlayer = (i: number) => (e: InputEvent) => {
        const newPlayers = [...players];
        if (e.target instanceof HTMLInputElement) {
            newPlayers[i] = e.target.value;
        }
        setPlayers(newPlayers);
    };

    const handleAddPlayers = () => {
        setNumPlayers(numPlayers + 1);
    };

    const handleChangeTakes = (rowIndex: number, player: number, field: 'request' | 'taken') => (e: InputEvent) => {
        if (e.target instanceof HTMLInputElement) {
            let row = rows[rowIndex];
            const type = rowTypes[rowIndex];
            let maxCount: number;
            if (typeof type === 'number') {
                maxCount = type;
            } else {
                maxCount = Math.floor(numCards / numPlayers);
            }
            if (!row) {
                row = [];
            }
            let value: string | number = e.target.value;
            let isBlind = type === 'Т' || row[player]?.isBlind;
            if (type !== 'Т' && value.toLowerCase().includes('b')) {
                isBlind = !isBlind;
            }
            value = value.replace(/[^-0-9]/g, '');
            value = Math.abs(parseInt(value));
            if (value >= maxCount) {
                value = maxCount;
            }
            if (isNaN(value)) {
                value = 0;
            }
            if (value === 0) {
                value = '-';
            }
            row[player] = {
                ...row[player],
                [field]: value,
                isBlind,
            }

            const newRows = [...rows];
            newRows[rowIndex] = row;

            setRows(newRows);
        }
    };

    return <>
        <table>
            <thead>
                <th />
                {range(numPlayers).map(i => (
                    <th key={i} colSpan={3} class="first">
                        <input
                            type='text'
                            value={players[i]}
                            onInput={handleSetPlayer(i)}
                            autoComplete='off'
                        />
                    </th>
                ))}
                <th class="flex-row">
                    <button onClick={handleAddPlayers}>+</button>
                </th>
            </thead>
            <tbody>
                {rowTypes.map((rt, i) => (
                    <tr
                        class={`${(rt === 'Т' || i === 0) ? 'first' : ''}`}
                        key={i}>
                        <td>{rt}</td>
                        {range(numPlayers).map(p => (
                            <>
                                <td class="request first">
                                    <input
                                        class={`${rowTypes[i] === 'Т' || rows[i]?.[p]?.isBlind ? 'blind' : ''}`}
                                        value={rows[i]?.[p]?.request ?? ''}
                                        onInput={handleChangeTakes(i, p, 'request')}
                                        size={2}
                                        autoComplete='off'
                                    />
                                </td>
                                <td class="request">
                                    <input
                                        value={rows[i]?.[p]?.taken ?? ''}
                                        onInput={handleChangeTakes(i, p, 'taken')}
                                        size={2}
                                        autoComplete='off'
                                    />
                                </td>
                                <td>
                                    {points[i]?.[p]}
                                </td>
                            </>
                        ))}

                        <td>{mismatches[i]}</td>
                    </tr>
                ))}</tbody>
        </table>
    </>;
};
