import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import CustomTextSymbol from '../symbols/customTextSymbol.js';
import Rule from './rule.js';
class MysteryRule extends Rule {
    /**
     * **Mystery: alternate solution**
     */
    constructor(solution, visible) {
        super();
        Object.defineProperty(this, "solution", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: solution
        });
        Object.defineProperty(this, "visible", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: visible
        });
        this.solution = MysteryRule.cleanSolution(solution);
        this.visible = visible;
    }
    get id() {
        return `mystery`;
    }
    get explanation() {
        return `*Mystery:* Alternate solution`;
    }
    get visibleWhenSolving() {
        return this.visible;
    }
    get configs() {
        return MysteryRule.CONFIGS;
    }
    createExampleGrid() {
        return MysteryRule.EXAMPLE_GRID;
    }
    get searchVariants() {
        return MysteryRule.SEARCH_VARIANTS;
    }
    validateGrid(grid) {
        if (grid.colorEquals(this.solution))
            return { state: State.Satisfied };
        return { state: State.Incomplete };
    }
    get necessaryForCompletion() {
        return false;
    }
    onFinalValidation(grid, _solution, state) {
        if (state.final === State.Satisfied)
            return state;
        if (grid.colorEquals(this.solution))
            return {
                final: State.Satisfied,
                symbols: state.symbols,
                rules: state.rules,
            };
        return state;
    }
    onGridChange(newGrid) {
        if (newGrid.width === this.solution.width &&
            newGrid.height === this.solution.height) {
            if (!newGrid.tiles.some((row, y) => row.some((tile, x) => {
                const solutionTile = this.solution.getTile(x, y);
                if (solutionTile.exists !== tile.exists)
                    return true;
                if (solutionTile.fixed !== tile.fixed)
                    return true;
                if (solutionTile.exists &&
                    solutionTile.fixed &&
                    solutionTile.color !== tile.color)
                    return true;
                return false;
            })))
                return this;
        }
        return this.withSolution(MysteryRule.cleanSolution(this.solution, newGrid));
    }
    onGridResize(_grid, mode, direction, index) {
        if (mode === 'insert') {
            if (direction === 'row') {
                return this.withSolution(this.solution.insertRow(index));
            }
            else if (direction === 'column') {
                return this.withSolution(this.solution.insertColumn(index));
            }
        }
        else if (mode === 'remove') {
            if (direction === 'row') {
                return this.withSolution(this.solution.removeRow(index));
            }
            else if (direction === 'column') {
                return this.withSolution(this.solution.removeColumn(index));
            }
        }
        return this;
    }
    copyWith({ solution, visible, }) {
        return new MysteryRule(solution ?? this.solution, visible ?? this.visible);
    }
    withSolution(solution) {
        return this.copyWith({ solution });
    }
    withVisible(visible) {
        return this.copyWith({ visible });
    }
    static cleanSolution(solution, baseGrid) {
        const tiles = baseGrid
            ? array(baseGrid.width, baseGrid.height, (x, y) => {
                const tile = baseGrid.getTile(x, y);
                if (!tile.exists || tile.fixed)
                    return tile;
                const solutionTile = solution.getTile(x, y);
                if (!solutionTile.exists || solutionTile.color === Color.Gray)
                    return tile;
                return tile.withColor(solutionTile.color);
            })
            : solution.tiles;
        return new GridData(baseGrid?.width ?? solution.width, baseGrid?.height ?? solution.height, tiles);
    }
}
Object.defineProperty(MysteryRule, "EXAMPLE_GRID", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze(GridData.create(['.']).addSymbol(new CustomTextSymbol('', GridData.create([]), 0, 0, '?')))
});
Object.defineProperty(MysteryRule, "CONFIGS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: Object.freeze([
        {
            type: ConfigType.Tile,
            default: MysteryRule.EXAMPLE_GRID,
            resizable: false,
            field: 'solution',
            description: 'Solution',
            configurable: true,
        },
        {
            type: ConfigType.Boolean,
            default: true,
            field: 'visible',
            description: 'Visible',
            configurable: true,
        },
    ])
});
Object.defineProperty(MysteryRule, "SEARCH_VARIANTS", {
    enumerable: true,
    configurable: true,
    writable: true,
    value: [
        new MysteryRule(MysteryRule.EXAMPLE_GRID, true).searchVariant(),
    ]
});
export default MysteryRule;
export const instance = new MysteryRule(GridData.create([]), true);
