import { onMounted, ref } from "vue";

import type { AppInfo, DemoPackSummary, PlayerView, TurnIntent, TurnRequest } from "@contracts";

import {
  forkBranch as forkRuntimeBranch,
  getAppInfo,
  getDemoPackSummary,
  getDemoPlayerView,
  submitTurn as submitRuntimeTurn
} from "./bridge";

function errorMessage(reason: unknown): string {
  if (reason instanceof Error) return reason.message;
  if (
    typeof reason === "object" &&
    reason !== null &&
    "message" in reason &&
    typeof reason.message === "string"
  ) {
    return reason.message;
  }
  return String(reason);
}

export function useDemo() {
  const appInfo = ref<AppInfo | null>(null);
  const pack = ref<DemoPackSummary | null>(null);
  const playerView = ref<PlayerView | null>(null);
  const loading = ref(true);
  const error = ref<string | null>(null);
  const busy = ref(false);
  const turnError = ref<string | null>(null);
  const lastSubmittedIntent = ref<TurnIntent | null>(null);

  onMounted(async () => {
    try {
      [appInfo.value, pack.value, playerView.value] = await Promise.all([
        getAppInfo(),
        getDemoPackSummary(),
        getDemoPlayerView()
      ]);
    } catch (reason) {
      error.value = errorMessage(reason);
    } finally {
      loading.value = false;
    }
  });

  async function submitTurn(intent: "speak_or_act", input: string): Promise<void>;
  async function submitTurn(intent: "continue", input?: ""): Promise<void>;
  async function submitTurn(intent: "speak_or_act" | "continue", input = ""): Promise<void> {
    const currentView = playerView.value;
    const normalizedInput = input.trim();

    if (!currentView || busy.value || (intent === "speak_or_act" && !normalizedInput)) return;

    const request: TurnRequest = {
      storyId: currentView.storyId,
      branchId: currentView.branchId,
      expectedNodeId: currentView.nodeId,
      actionId: `demo_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
      intent,
      input: intent === "continue" ? "" : normalizedInput
    };

    busy.value = true;
    turnError.value = null;
    lastSubmittedIntent.value = intent;

    try {
      const result = await submitRuntimeTurn(request, currentView);
      playerView.value = result.playerView;
    } catch (reason) {
      turnError.value = errorMessage(reason);
    } finally {
      busy.value = false;
    }
  }

  async function forkBranch(sourceNodeId: string): Promise<void> {
    const currentView = playerView.value;
    if (!currentView || busy.value || sourceNodeId === currentView.nodeId) return;

    busy.value = true;
    turnError.value = null;
    lastSubmittedIntent.value = null;

    try {
      const result = await forkRuntimeBranch(
        {
          storyId: currentView.storyId,
          currentBranchId: currentView.branchId,
          expectedCurrentNodeId: currentView.nodeId,
          sourceNodeId,
          actionId: `fork_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
        },
        currentView
      );
      playerView.value = result.playerView;
    } catch (reason) {
      turnError.value = errorMessage(reason);
    } finally {
      busy.value = false;
    }
  }

  return {
    appInfo,
    busy,
    error,
    lastSubmittedIntent,
    loading,
    pack,
    playerView,
    forkBranch,
    submitTurn,
    turnError
  };
}
