type Dir = "U" | "D" | "L" | "R"
type PipeType = "." | "|" | "7" | "J" | "F" | "L" | "-" | "S";

type MoveState = {
    fromDir: Dir,
    curX: number,
    curY: number,
}

const transitionTable: Record<Dir, Record<PipeType, Dir | null>> = {
    "U": {
        "|": "U",
        "7": "L",
        "F": "R",
        ".": null,
        "J": null,
        "L": null,
        "-": null,
        "S": null
    },
    "D": {
        "|": "D",
        "7": null,
        "F": null,
        ".": null,
        "J": "L",
        "L": "R",
        "-": null,
        "S": null
    },
    "L": {
        "|": null,
        "7": null,
        "F": "D",
        ".": null,
        "J": null,
        "L": "U",
        "-": "L",
        "S": null,
    },
    "R": {
        "|": null,
        "7": "D",
        "F": null,
        ".": null,
        "J": "U",
        "L": null,
        "-": "R",
        "S": null
    }
}

function getNextState(pipeMap: PipeType[][], state: MoveState) {
    const curPipe = pipeMap[state.curY][state.curX];
    const nextDir = transitionTable[state.fromDir][curPipe];
    if (nextDir === null) {
        return null;
    }
    switch (nextDir) {
        case "U":
            state.curY--;
            break;
        case "D":
            state.curY++;
            break;
        case "L":
            state.curX--;
            break;
        case "R":
            state.curX++;
            break;
    }
    state.fromDir = nextDir;
    return state;
}

const input = await Deno.readTextFile("input.txt");
const lines = input.split("\n").map(x => x.trim()).filter(x => x.length > 0);
const pipeMap = lines.map(x => {
    return x.split("");
}) as PipeType[][];
let startX = 0, startY = 0;
startY = pipeMap.findIndex(pipeLine => {
    const xIndex = pipeLine.findIndex(x => x === "S")
    if (xIndex !== -1) {
        startX = xIndex;
        return true;
    }
    return false;
});

console.log(startX, startY);

const stepMap: any[][] = new Array(pipeMap.length).fill(Infinity).map(_ => new Array(pipeMap[0].length).fill(Infinity));

function stepMaptoStr(stepMap: number[][]){
    return stepMap.map(line => line.map(x=> isFinite(x) ? x : ".").join(",")).join("\n");
}

function iterateStep(pipeMap: PipeType[][], 
    state: MoveState, 
    fn: (state: MoveState) => void) {
    fn({...state});
    while (true) {
        const nextState = getNextState(pipeMap,{...state});
        if (nextState === null) {
            throw new Error("dead end at " + state.curX + "," + state.curY);
        }
        if (pipeMap[nextState.curY][nextState.curX] === "S") {
            return;
        }
        fn(nextState);
        state = nextState;
    }
}

const initStates = [
    // {
    //     fromDir: "U",
    //     curX: startX,
    //     curY: startY - 1,
    // },
    // {
    //     fromDir: "R",
    //     curX: startX + 1,
    //     curY: startY,
    // },
    {
        fromDir: "D",
        curX: startX,
        curY: startY + 1,
    },
    {
        fromDir: "L",
        curX: startX - 1,
        curY: startY,
    }
] as MoveState[];

for (const initState of initStates) {
    // const index = initStates.indexOf(initState);
    try {
        let stepCount = 0;
        iterateStep(pipeMap, {...initState}, (state) => {
            if (state.curX === startX && state.curY === startY) {
                console.log("?",stepCount, state);
            }
            stepMap[state.curY][state.curX] = Math.min(++stepCount, stepMap[state.curY][state.curX]);
        });
    }
    catch(e) {
        console.log("error",initState);
    }
}
await Deno.writeTextFile("stepMap.csv",stepMaptoStr(stepMap));
console.log(Math.max(...stepMap.map(line=> Math.max(...line.map(x=> isFinite(x) ? x : -1)))))
