// #region UseReviewSession [C:3] [TYPE Module] [SEMANTICS dataset-review, session, api, handlers]
// @BRIEF Composable for dataset review session state management — load, update, export, and clarify.
// @RELATION DEPENDS_ON -> [ApiModule]
// @RELATION DEPENDS_ON -> [DatasetReviewApi]
// @RELATION BINDS_TO -> [EXT:frontend:datasetReviewSessionStore]
// @RELATION BINDS_TO -> [EXT:frontend:assistantChatStore]
import { goto } from "$app/navigation";
import { api } from "$lib/api";
import {
  extractDatasetReviewVersion,
  getDatasetReviewConflictMessage,
  isDatasetReviewConflictError,
  normalizeDatasetReviewDetail,
  requestDatasetReviewApi,
} from "$lib/api/datasetReview";
import {
  datasetReviewSessionStore,
  setLoading,
  setError,
  setSession,
  resetSession,
} from "$lib/stores/datasetReviewSession.svelte.js";
import {
  assistantChatStore,
  setAssistantDatasetReviewSessionId,
  setAssistantSeedMessage,
  setAssistantFocusTarget,
} from "$lib/stores/assistantChat.svelte.js";

interface SessionDetail {
  session_id?: string;
  dataset_ref?: string;
  version?: number;
  session_version?: number;
  previews?: unknown[];
  preview?: Record<string, unknown>;
  semantic_fields?: unknown[];
  execution_mappings?: unknown[];
  clarification_sessions?: unknown[];
  readiness_state?: string;
  recommended_action?: string;
  status?: string;
  [key: string]: unknown;
}

interface ClarificationState {
  [key: string]: unknown;
}

interface SessionLoadResult {
  session: SessionDetail | null;
  clarificationState: ClarificationState | null;
  loadError: string;
  previewUiState?: string;
}

interface ClarificationQuestion {
  question_id?: string;
  question_text?: string;
  [key: string]: unknown;
}

interface SourceSubmitResult {
  intakeAcknowledgment: boolean;
  submitError: string;
  loadError: string;
  isSubmitting: boolean;
}

interface LifecycleResult {
  loadError: string;
}

interface ExportResult {
  exportMessage: string;
  isExporting: boolean;
}

interface PreviewUpdateResult {
  session: SessionDetail | null;
  previewUiState: string;
}

interface SemanticUpdateResult {
  session: SessionDetail | null;
}

interface MappingUpdateResult {
  session: SessionDetail | null;
  previewUiState: string;
}

interface LaunchUpdateResult {
  launchResult: Record<string, unknown> | null;
}

interface ReviewSessionApi {
  loadSessionDetail: (sessionId: string) => Promise<SessionLoadResult>;
  loadClarificationState: (session: SessionDetail) => Promise<ClarificationState | null>;
  handleSourceSubmit: (session: SessionDetail | null, intakeAcknowledgment: boolean, submitError: string, loadError: string, isSubmitting: boolean) => SourceSubmitResult;
  handleResumeSession: (sessionId: string, sessionVersion?: number) => Promise<LifecycleResult>;
  updateSessionLifecycle: (sessionId: string, statusValue: string, sessionVersion?: number) => Promise<LifecycleResult>;
  exportArtifact: (sessionId: string, kind: string, format: string) => Promise<ExportResult>;
  handlePreviewUpdated: (session: SessionDetail | null, result: Record<string, unknown> | null) => PreviewUpdateResult;
  handleSemanticUpdated: (session: SessionDetail | null, result: Record<string, unknown> | null) => SemanticUpdateResult;
  handleMappingUpdated: (session: SessionDetail | null, result: Record<string, unknown> | null) => MappingUpdateResult;
  handleLaunchUpdated: (result: Record<string, unknown> | null) => LaunchUpdateResult;
  handleSectionJump: (target: string) => void;
  handleAskAiContext: (payload: Record<string, unknown> | null | undefined, setAssistantFocusTargetFn: (p: { target: string; source: string }) => void, setAssistantSeedMessageFn: (msg: string) => void) => void;
  primaryActionHandler: (session: SessionDetail | null, clarificationCurrentQuestion: ClarificationQuestion | null, assistantSeedPrompt: string, handleResumeSessionFn: () => void, handleAskAiContextFn: (p: Record<string, unknown>) => void) => void;
  buildSessionUrl: (sessionId: string) => string;
}

export function useReviewSession(): ReviewSessionApi {
  return {
    loadSessionDetail,
    loadClarificationState,
    handleSourceSubmit,
    handleResumeSession,
    updateSessionLifecycle,
    exportArtifact,
    handlePreviewUpdated,
    handleSemanticUpdated,
    handleMappingUpdated,
    handleLaunchUpdated,
    handleSectionJump,
    handleAskAiContext,
    primaryActionHandler,
    buildSessionUrl,
  };
}

function buildSessionUrl(sessionId: string): string {
  return `/datasets/review/${encodeURIComponent(String(sessionId))}`;
}

async function loadSessionDetail(sessionId: string): Promise<SessionLoadResult> {
  if (!sessionId) {
    return { session: null, clarificationState: null, loadError: "" };
  }

  setLoading(true);
  let sessionResult: SessionDetail | null = null;
  let clarificationResult: ClarificationState | null = null;
  let error = "";
  let previewUi = "";

  try {
    const detail = await api.fetchApi<SessionDetail>(`/dataset-orchestration/sessions/${sessionId}`);
    sessionResult = normalizeDatasetReviewDetail(detail);
    previewUi = "";
    setSession(sessionResult);
    setAssistantDatasetReviewSessionId(sessionResult?.session_id || null);
    clarificationResult = await loadClarificationStateInline(sessionResult);
  } catch (err: unknown) {
    error = (err as { message?: string })?.message || "Failed to load session";
    setError(error);
  } finally {
    setLoading(false);
  }

  return { session: sessionResult, clarificationState: clarificationResult, loadError: error, previewUiState: previewUi };
}

async function loadClarificationStateInline(sessionDetail: SessionDetail | null): Promise<ClarificationState | null> {
  if (!sessionDetail?.session_id || !sessionDetail?.clarification_sessions?.length) return null;
  try {
    return await api.fetchApi<ClarificationState>(
      `/dataset-orchestration/sessions/${sessionDetail.session_id}/clarification`,
    );
  } catch (_error: unknown) {
    return null;
  }
}

// Re-export for external use
const loadClarificationState = loadClarificationStateInline;

async function handleSourceSubmit(
  session: SessionDetail | null,
  intakeAcknowledgment: boolean,
  submitError: string,
  loadError: string,
  isSubmitting: boolean
): Promise<SourceSubmitResult> {
  // This is handled inline in the page — returns a operation object
  return { intakeAcknowledgment, submitError, loadError, isSubmitting };
}

async function handleResumeSession(sessionId: string, sessionVersion?: number): Promise<LifecycleResult> {
  if (!sessionId) return { loadError: "" };
  try {
    const updated = await requestDatasetReviewApi<{ session_id: string }>(
      `/dataset-orchestration/sessions/${sessionId}`, "PATCH",
      { status: "active" }, sessionVersion,
    );
    await goto(buildSessionUrl(updated.session_id));
    return { loadError: "" };
  } catch (error: unknown) {
    const err = error as { message?: string };
    const msg = (isDatasetReviewConflictError(error)
      ? getDatasetReviewConflictMessage(error)
      : err?.message) || "Failed to resume session";
    return { loadError: msg };
  }
}

async function updateSessionLifecycle(sessionId: string, statusValue: string, sessionVersion?: number): Promise<LifecycleResult> {
  if (!sessionId) return { loadError: "" };
  try {
    await requestDatasetReviewApi(
      `/dataset-orchestration/sessions/${sessionId}`, "PATCH",
      { status: statusValue }, sessionVersion,
    );
    return { loadError: "" };
  } catch (error: unknown) {
    const err = error as { message?: string };
    const msg = (isDatasetReviewConflictError(error)
      ? getDatasetReviewConflictMessage(error)
      : err?.message) || "Failed to save session";
    return { loadError: msg };
  }
}

async function exportArtifact(sessionId: string, kind: string, format: string): Promise<ExportResult> {
  if (!sessionId) return { exportMessage: "", isExporting: false };
  try {
    const artifact = await api.fetchApi<{ artifact_type?: string; format?: string; storage_ref?: string }>(
      `/dataset-orchestration/sessions/${sessionId}/exports/${kind}?format=${format}`,
    );
    return { exportMessage: `${artifact.artifact_type} • ${artifact.format} • ${artifact.storage_ref}`, isExporting: false };
  } catch (error: unknown) {
    return { exportMessage: (error as { message?: string })?.message || "Export failed", isExporting: false };
  }
}

function handlePreviewUpdated(session: SessionDetail | null, result: Record<string, unknown> | null): PreviewUpdateResult {
  if (!session || !result?.preview) return { session: null, previewUiState: "" };
  const previewUiState = (result.preview_state as string) || (result.preview as Record<string, unknown>)?.preview_status as string || "";
  const existingPreviews = session.previews || [];
  const preview = result.preview as Record<string, unknown>;
  const previewId = preview.preview_id;
  const nextPreviews = existingPreviews.some(
    (item: unknown) => (item as Record<string, unknown>).preview_id === previewId,
  )
    ? existingPreviews.map((item: unknown) =>
        (item as Record<string, unknown>).preview_id === previewId ? preview : item,
      )
    : [...existingPreviews, preview];
  return {
    session: {
      ...session,
      session_version: extractDatasetReviewVersion(preview) ?? session.session_version,
      version: extractDatasetReviewVersion(preview) ?? session.version,
      previews: nextPreviews as unknown[],
      preview: preview,
      readiness_state:
        preview.preview_status === "ready"
          ? session.readiness_state === "run_ready" ? "run_ready" : "compiled_preview_ready"
          : session.readiness_state,
    },
    previewUiState,
  };
}

function handleSemanticUpdated(session: SessionDetail | null, result: Record<string, unknown> | null): SemanticUpdateResult {
  if (!session || !result) return { session: null };
  const nextVersion = extractDatasetReviewVersion(result);
  let updatedSession: SessionDetail = { ...session };
  if (Array.isArray(result?.fields)) {
    updatedSession.semantic_fields = result.fields;
    updatedSession = applySessionVersionInline(updatedSession, nextVersion);
  } else if (result.field_id) {
    updatedSession.semantic_fields = mergeCollectionItemInline(updatedSession.semantic_fields || [], result, "field_id");
    updatedSession = applySessionVersionInline(updatedSession, nextVersion);
  }
  return { session: updatedSession };
}

function handleMappingUpdated(session: SessionDetail | null, result: Record<string, unknown> | null): MappingUpdateResult {
  if (!session || !result) return { session: null, previewUiState: "" };
  const nextVersion = extractDatasetReviewVersion(result);
  let updatedSession: SessionDetail = { ...session };
  let previewUiState = "";
  if (Array.isArray(result?.mappings)) {
    updatedSession.execution_mappings = result.mappings;
    updatedSession = applySessionVersionInline(updatedSession, nextVersion);
  } else if (result.mapping_id || result.mapping) {
    const mapping = (result.mapping as Record<string, unknown>) || result;
    updatedSession.execution_mappings = mergeCollectionItemInline(updatedSession.execution_mappings || [], mapping, "mapping_id");
    updatedSession = applySessionVersionInline(updatedSession, nextVersion);
  }
  if (result.preview_state) previewUiState = result.preview_state as string;
  return { session: updatedSession, previewUiState };
}

function handleLaunchUpdated(result: Record<string, unknown> | null): LaunchUpdateResult {
  return { launchResult: (result?.launch_result as Record<string, unknown>) || result || null };
}

function handleSectionJump(target: string): void {
  const normalizedTarget: Record<string, string> = {
    preview: "sql-preview", "sql-preview": "sql-preview",
    mappings: "mapping", mapping: "mapping",
    semantics: "semantics", summary: "summary",
    clarification: "assistant-chat", filters: "summary",
    intake: "summary", "next-action": "next-action",
  };
  const elId = normalizedTarget[target] || target;
  document.getElementById(elId)?.scrollIntoView({ behavior: "smooth", block: "start" });
}

function handleAskAiContext(
  payload: Record<string, unknown> | null | undefined,
  setAssistantFocusTargetFn: (p: { target: string; source: string }) => void,
  setAssistantSeedMessageFn: (msg: string) => void
): void {
  if (!payload) return;
  if (payload.target) {
    setAssistantFocusTargetFn({ target: payload.target as string, source: "workspace_context_action" });
  }
  setAssistantSeedMessageFn(buildAssistantContextPromptInline(payload));
  document.getElementById("assistant-chat")?.scrollIntoView({ behavior: "smooth", block: "start" });
}

function primaryActionHandler(
  session: SessionDetail | null,
  clarificationCurrentQuestion: ClarificationQuestion | null,
  assistantSeedPrompt: string,
  handleResumeSessionFn: () => void,
  handleAskAiContextFn: (p: Record<string, unknown>) => void
): void {
  if (!session) return;
  if (session.recommended_action === "resume_session") { handleResumeSessionFn(); return; }
  if (session.recommended_action === "generate_sql_preview") {
    handleAskAiContextFn({
      target: "sql-preview", section: "sql-preview",
      label: "sql-preview",
      prompt: "Explain which approvals or fixes are still required before regenerating SQL preview.",
    });
    document.getElementById("sql-preview")?.scrollIntoView({ behavior: "smooth", block: "start" });
    return;
  }
  if (session.recommended_action === "launch_dataset") {
    document.getElementById("launch")?.scrollIntoView({ behavior: "smooth", block: "start" });
    return;
  }
  handleAskAiContextFn({
    target: clarificationCurrentQuestion?.question_id ? `clarification:${clarificationCurrentQuestion.question_id}` : "clarification",
    section: "clarification",
    prompt: assistantSeedPrompt,
  });
}

function buildAssistantContextPromptInline(payload: Record<string, unknown>): string {
  const label = (payload?.label as string) || (payload?.target as string) || "current item";
  const section = (payload?.section as string) || "workspace";
  const context = String(payload?.prompt || "").trim();
  if (payload?.mode === "improve") {
    return `Improve ${label}. Section: ${section}.${context ? ` Context: ${context}` : ""}`;
  }
  return `Help review ${label}. Section: ${section}.${context ? ` Context: ${context}` : ""}`;
}

function applySessionVersionInline(sessionObj: SessionDetail, nextVersion: number | null | undefined): SessionDetail {
  if (nextVersion === null || nextVersion === undefined) return sessionObj;
  return { ...sessionObj, session_version: nextVersion, version: nextVersion };
}

function mergeCollectionItemInline(collection: unknown[] = [], item: Record<string, unknown> | null = null, idKey = "id"): unknown[] {
  if (!item) return collection;
  const itemId = item?.[idKey];
  if (!itemId) return collection;
  return collection.some((entry: unknown) => (entry as Record<string, unknown>)?.[idKey] === itemId)
    ? collection.map((entry: unknown) => ((entry as Record<string, unknown>)?.[idKey] === itemId ? { ...(entry as Record<string, unknown>), ...item } : entry))
    : [...collection, item];
}
// #endregion UseReviewSession
