// #region Datasets.ReviewModel [C:4] [TYPE Model] [SEMANTICS dataset-review,workspace,session,model]
// @ingroup Datasets
// @BRIEF Screen model for dataset review workspace — atoms, derived state, and action delegates.
// @INVARIANT sessionVersion gates stale concurrent updates — discarded if mismatch.
// @INVARIANT bootstrapping blocks all user interactions until session loaded.
// @STATE empty     — No session, SourceIntakePanel visible.
// @STATE importing — Session being created, milestones panel shown.
// @STATE review    — Session active, 3-column layout with findings, mappings, assistant.
// @STATE error     — loadError or submitError displayed.
// @ACTION bootstrap(routeSessionId)           — Initialize env + load session from API.
// @ACTION handleSourceSubmit(payload)         — POST new session, return sessionId for navigation.
// @ACTION handleResumeSession()               — PATCH session to active.
// @ACTION updateSessionLifecycle(statusValue) — Pause/archive session.
// @ACTION handleExportArtifact(kind, format)  — Export artifact, store message.
// @ACTION handlePreviewUpdated(result)        — Merge preview into session.
// @ACTION handleSemanticUpdated(result)       — Merge semantic fields.
// @ACTION handleMappingUpdated(result)        — Merge execution mappings.
// @ACTION handleLaunchUpdated(result)         — Store launch result.
// @RELATION DEPENDS_ON -> [UseReviewSession]
// @RELATION DEPENDS_ON -> [ApiModule]
// @RELATION DEPENDS_ON -> [DatasetReviewApi]

import { api } from '$lib/api.js';
import { initializeEnvironmentContext } from '$lib/stores/environmentContext.svelte.js';
import { datasetReviewSessionStore } from '$lib/stores/datasetReviewSession.svelte.js';
import { useReviewSession } from '$lib/api/dataset-review/useReviewSession.js';
import { buildImportMilestones, buildWorkspaceLaunchBlockers, buildAssistantSeedPrompt, buildAssistantContextPrompt } from '$lib/helpers/review-workspace-helpers.js';
import { getT } from '$lib/i18n/index.svelte.js';

// ── Types ────────────────────────────────────────────────────────

type WorkspaceState = 'empty' | 'importing' | 'review' | 'error';

interface ReviewSession {
  session_id?: string;
  dataset_ref?: string;
  environment_id?: string;
  profile?: Record<string, unknown> | null;
  findings?: Array<{ severity: string; resolution_state?: string }>;
  imported_filters?: unknown[];
  previews?: unknown[];
  execution_mappings?: Array<{ requires_explicit_approval?: boolean; approval_state?: string }>;
  run_contexts?: unknown[];
  semantic_fields?: unknown[];
  semantic_sources?: unknown[];
  template_variables?: unknown[];
  readiness_state?: string;
  recommended_action?: string;
  current_phase?: string;
  session_version?: number;
  version?: number;
  [key: string]: unknown;
}

interface ClarificationState {
  clarification_session?: { remaining_count?: number; resolved_count?: number };
  current_question?: { question_id?: string; [key: string]: unknown } | null;
  [key: string]: unknown;
}

// ── Model ────────────────────────────────────────────────────────

export class DatasetReviewModel {
  // ── Atoms ──────────────────────────────────────────────────
  session: ReviewSession | null = $state(null);
  loadError: string = $state('');
  submitError: string = $state('');
  exportMessage: string = $state('');
  isBootstrapping: boolean = $state(true);
  isSubmitting: boolean = $state(false);
  isExporting: boolean = $state(false);
  intakeAcknowledgment: string = $state('');
  clarificationState: ClarificationState | null = $state(null);
  previewUiState: string = $state('');
  launchResult: Record<string, unknown> | null = $state(null);
  assistantPromptNonce: number = $state(0);

  // ── Composable ─────────────────────────────────────────────
  private _reviewSession = useReviewSession();

  // ── Derived — session-derived ──────────────────────────────
  currentWorkspaceState: WorkspaceState = $derived(
    !this.session
      ? (this.isSubmitting ? 'importing' : 'empty')
      : this.session.readiness_state === 'importing' ? 'importing' : 'review',
  );
  profile = $derived(this.session?.profile || null);
  findings = $derived(this.session?.findings || []);
  importedFilters = $derived(this.session?.imported_filters || []);
  latestPreview = $derived(
    this.session?.previews?.length
      ? this.session.previews[this.session.previews.length - 1]
      : null,
  );
  executionMappings = $derived(this.session?.execution_mappings || []);
  latestRunContext = $derived(this.session?.run_contexts?.length
    ? this.session.run_contexts[this.session.run_contexts.length - 1]
    : null,
  );
  sessionVersion = $derived(this.session?.session_version ?? this.session?.version ?? null);

  // ── Derived — clarification ────────────────────────────────
  clarificationSession = $derived(this.clarificationState?.clarification_session || null);
  clarificationCurrentQuestion = $derived(this.clarificationState?.current_question || null);
  clarificationRemainingCount = $derived(Number(this.clarificationSession?.remaining_count || 0));
  clarificationTotalCount = $derived(
    this.clarificationRemainingCount + Number(this.clarificationSession?.resolved_count || 0),
  );

  // ── Derived — preview / UI ─────────────────────────────────
  previewGateState = $derived(
    String(this.previewUiState || this.latestPreview?.preview_status || 'missing'),
  );

  // ── Derived — button states ────────────────────────────────
  exportDisabled = $derived(!this.session || this.isExporting);
  saveDisabled = $derived(!this.session || this.isSubmitting);
  launchDisabled = $derived(!this.session || this.isSubmitting || this.isExporting);

  // ── Derived — counts ───────────────────────────────────────
  blockingCount = $derived(this.findings.filter((f: { severity: string }) => f.severity === 'blocking').length);
  warningCount = $derived(this.findings.filter((f: { severity: string }) => f.severity === 'warning').length);
  infoCount = $derived(this.findings.filter((f: { severity: string }) => f.severity === 'informational').length);
  unresolvedBlockingFindingsCount = $derived(
    this.findings.filter(
      (f: { severity: string; resolution_state?: string }) =>
        f.severity === 'blocking'
        && f.resolution_state !== 'resolved'
        && f.resolution_state !== 'approved',
    ).length,
  );
  pendingApprovalMappingsCount = $derived(
    this.executionMappings.filter(
      (m: { requires_explicit_approval?: boolean; approval_state?: string }) =>
        m.requires_explicit_approval && m.approval_state !== 'approved',
    ).length,
  );

  // ── Derived — helpers (i18n-dependent) ─────────────────────
  readinessLabel = $derived(this._getReadinessLabel());
  importMilestones = $derived(this._buildImportMilestones());
  workspaceLaunchBlockers = $derived(this._buildLaunchBlockers());
  assistantSeedPrompt = $derived(this._buildSeedPrompt());
  workspaceFocusTarget = $derived(
    (datasetReviewSessionStore.value as { focusTarget?: string | null })?.focusTarget || null,
  );

  // ── Private derived helpers ────────────────────────────────
  private _i18n = () => getT();

  private _getReadinessLabel(): string {
    const t = this._i18n();
    const labels = t.dataset_review?.workspace?.readiness;
    return labels?.[this.session?.readiness_state || 'empty']
      || this.session?.readiness_state
      || t.dataset_review?.workspace?.empty_state_title
      || '';
  }

  private _buildImportMilestones() {
    return buildImportMilestones(
      this._i18n(), this.intakeAcknowledgment, this.session,
      this.importedFilters, this.latestPreview, this.profile,
      this.findings, this.currentWorkspaceState,
    );
  }

  private _buildLaunchBlockers() {
    return buildWorkspaceLaunchBlockers(
      this._i18n(), this.session, this.unresolvedBlockingFindingsCount,
      this.pendingApprovalMappingsCount, this.previewGateState,
    );
  }

  private _buildSeedPrompt() {
    return buildAssistantSeedPrompt(
      this._i18n(), this.session, this.profile,
      this.workspaceLaunchBlockers, this.clarificationCurrentQuestion,
      this.importedFilters,
    );
  }

  // ── Actions ────────────────────────────────────────────────

  /**
   * Bootstrap workspace: initialize env context and load session detail.
   * @POST session, clarificationState, loadError, previewUiState updated.
   */
  async bootstrap(routeSessionId: string): Promise<void> {
    this.isBootstrapping = true;
    await initializeEnvironmentContext();
    const result = await this._reviewSession.loadSessionDetail(routeSessionId);
    if (result) {
      this.session = result.session as ReviewSession | null;
      this.clarificationState = result.clarificationState as ClarificationState | null;
      this.loadError = result.loadError;
      this.previewUiState = result.previewUiState || '';
    }
    this.isBootstrapping = false;
  }

  /**
   * Create a new session from source payload.
   * @RETURNS sessionId string for navigation, or null on failure.
   */
  async handleSourceSubmit(payload: Record<string, unknown>): Promise<string | null> {
    const t = this._i18n();
    this.isSubmitting = true;
    this.submitError = '';
    this.exportMessage = '';
    this.loadError = '';
    this.intakeAcknowledgment = payload.source_kind === 'superset_link'
      ? t.dataset_review?.source?.recognized_link_hint
      : t.dataset_review?.source?.dataset_selection_acknowledged;

    try {
      const summary = await api.postApi('/dataset-orchestration/sessions', payload) as { session_id?: string };
      const sessionId = summary?.session_id;
      if (!sessionId) {
        this.submitError = t.dataset_review?.source?.submit_failed || 'Failed to create session';
        return null;
      }
      // Load session detail for the new session
      const result = await this._reviewSession.loadSessionDetail(sessionId);
      if (result) {
        this.session = result.session as ReviewSession | null;
        this.clarificationState = result.clarificationState as ClarificationState | null;
        this.loadError = result.loadError;
        this.previewUiState = result.previewUiState || '';
      }
      return sessionId;
    } catch (error: unknown) {
      this.submitError = (error as { message?: string })?.message
        || t.dataset_review?.source?.submit_failed
        || t.common?.error
        || 'Submit failed';
      return null;
    } finally {
      this.isSubmitting = false;
    }
  }

  /**
   * Resume previously saved session (PATCH to active).
   * @POST loadError updated on failure.
   */
  async handleResumeSession(): Promise<void> {
    if (!this.session?.session_id) return;
    const { loadError: err } = await this._reviewSession.handleResumeSession(
      this.session.session_id, this.sessionVersion as number | undefined,
    );
    if (err) this.loadError = err;
  }

  /**
   * Pause/archive session lifecycle.
   * @POST loadError updated on failure.
   */
  async updateSessionLifecycle(statusValue: string): Promise<void> {
    if (!this.session?.session_id) return;
    const { loadError: err } = await this._reviewSession.updateSessionLifecycle(
      this.session.session_id, statusValue, this.sessionVersion as number | undefined,
    );
    if (err) this.loadError = err;
  }

  /**
   * Export session artifact (stored ref + metadata).
   * @POST exportMessage updated.
   */
  async handleExportArtifact(kind: string, format: string): Promise<void> {
    if (!this.session?.session_id) return;
    const result = await this._reviewSession.exportArtifact(
      this.session.session_id, kind, format,
    );
    this.exportMessage = result.exportMessage;
  }

  /** Merge preview update into session object. */
  handlePreviewUpdated(result: Record<string, unknown> | null): void {
    const updated = this._reviewSession.handlePreviewUpdated(
      this.session as Record<string, unknown> | null, result,
    );
    if (updated.session) {
      this.session = updated.session as ReviewSession | null;
      this.previewUiState = updated.previewUiState || '';
    }
  }

  /** Merge semantic field update into session. */
  handleSemanticUpdated(result: Record<string, unknown> | null): void {
    const updated = this._reviewSession.handleSemanticUpdated(
      this.session as Record<string, unknown> | null, result,
    );
    if (updated.session) this.session = updated.session as ReviewSession | null;
  }

  /** Merge execution mapping update into session. */
  handleMappingUpdated(result: Record<string, unknown> | null): void {
    const updated = this._reviewSession.handleMappingUpdated(
      this.session as Record<string, unknown> | null, result,
    );
    if (updated.session) {
      this.session = updated.session as ReviewSession | null;
      if (updated.previewUiState) this.previewUiState = updated.previewUiState;
    }
  }

  /** Store launch result. */
  handleLaunchUpdated(result: Record<string, unknown> | null): void {
    const updated = this._reviewSession.handleLaunchUpdated(result);
    if (updated.launchResult) this.launchResult = updated.launchResult as Record<string, unknown>;
  }

  /** Sync session from external store (e.g., WebSocket update). */
  syncFromStore(extSession: ReviewSession | null | undefined): void {
    if (!extSession?.session_id) return;
    if (extSession.session_id !== (this.session?.session_id || '')) return;
    const extVer = extSession.session_version ?? extSession.version ?? null;
    if (extVer === null || extVer === this.sessionVersion) return;
    this.session = extSession;
  }

  /** Build assistant context prompt from section metadata. */
  buildAssistantContextPrompt(payload: Record<string, unknown>): string {
    return buildAssistantContextPrompt(this._i18n(), payload);
  }

  /** Build session URL from session ID. */
  static buildSessionUrl(sessionId: string): string {
    return `/datasets/review/${encodeURIComponent(String(sessionId))}`;
  }
}
// #endregion Datasets.ReviewModel
