import { useCallback, useRef, useState } from 'react';

import type {
  Match3DClickItemRequest,
  Match3DRunSnapshot,
} from '../packages/shared/src/contracts/match3dRuntime';
import { Match3DRuntimeShell } from './components/match3d-runtime';
import {
  createLocalMatch3DRuntimeAdapter,
  type Match3DRuntimeAdapter,
  startLocalMatch3DRun,
} from './services/match3d-runtime';

type LocalMatch3DRuntimeSession = {
  adapter: Match3DRuntimeAdapter;
  initialRun: Match3DRunSnapshot;
};

function resolveClearCountParam() {
  const params = new URLSearchParams(window.location.search);
  const clearCountParam = params.get('clearCount') ?? params.get('count');
  const clearCount =
    clearCountParam === null ? 12 : Number.parseInt(clearCountParam, 10);
  return Number.isFinite(clearCount) && clearCount > 0 ? clearCount : 12;
}

function buildInitialRuntimeSession(): LocalMatch3DRuntimeSession {
  const initialRun = startLocalMatch3DRun(resolveClearCountParam());
  return {
    adapter: createLocalMatch3DRuntimeAdapter({ initialRun }),
    initialRun,
  };
}

export default function Match3DPlaygroundApp() {
  const runtimeSessionRef = useRef(buildInitialRuntimeSession());
  const [run, setRun] = useState<Match3DRunSnapshot>(
    runtimeSessionRef.current.initialRun,
  );

  const syncRun = useCallback((nextRun: Match3DRunSnapshot) => {
    setRun(nextRun);
  }, []);

  const handleClickItem = useCallback(async (payload: Match3DClickItemRequest) => {
    const runId = payload.runId ?? runtimeSessionRef.current.initialRun.runId;
    const result = await runtimeSessionRef.current.adapter.clickItem(runId, payload);
    setRun(result.run);
    return result;
  }, []);

  const handleRestart = useCallback(() => {
    void runtimeSessionRef.current.adapter.restartRun(run.runId).then(({ run }) => {
      setRun(run);
    });
  }, [run.runId]);

  const handleExit = useCallback(() => {
    window.location.assign('/');
  }, []);

  const handleTimeExpired = useCallback(() => {
    void runtimeSessionRef.current.adapter.finishTimeUp(run.runId).then(({ run }) => {
      setRun(run);
    });
  }, [run.runId]);

  return (
    <Match3DRuntimeShell
      run={run}
      onBack={handleExit}
      onRestart={handleRestart}
      onOptimisticRunChange={syncRun}
      onClickItem={handleClickItem}
      onTimeExpired={handleTimeExpired}
      error={null}
      isBusy={false}
    />
  );
}
