/**
 * Thread Form - Type definitions
 *
 * A conversational task-based form for tax document collection.
 * Replaces the complex FB form with a Karbon HQ-inspired thread approach.
 */
import type * as React from 'react';
import type { FileManagerConfig } from '../../types/file_manager.js';
import type { ViewSection, FieldMetadataInput, FieldMetadataChange, FieldActionComponents, FieldActionContext } from '../hazo_collab_form_view/types.js';
export type { FieldActionComponents, FieldActionContext };
export interface ThreadFormData {
    form_id: string;
    title: string;
    status: 'draft' | 'sent' | 'in_progress' | 'completed';
    created_at: string;
    updated_at: string;
    client: ThreadUser;
    agents: ThreadUser[];
    tasks: ThreadTask[];
    /** Agent-selected content IDs for export to HazoDataForm */
    collected_data_selections?: Record<string, boolean>;
}
export interface ThreadUser {
    name: string;
    id?: string;
    avatar_url?: string;
}
export interface ThreadTask {
    task_id: string;
    title: string;
    description: string;
    status: ThreadTaskStatus;
    completed_by?: string;
    completed_at?: string;
    sort_order: number;
    created_at: string;
    created_by: string;
    due_date?: string;
    thread: ThreadMessage[];
    /** Agent review status — set when client completes and agent reviews */
    agent_review?: 'pending_review' | 'approved' | 'reopened';
    /** Who reopened and why */
    reopened_by?: string;
    /** Group-level coverage results (e.g. periodic_coverage gap detection).
     *  Populated by handle_run_backoffice after per-file validation completes.
     *  One entry per (group, rule) combination — most tasks will have 0 or 1. */
    coverage_results?: import('./hooks/use_file_pipeline.js').GroupCoverageResult[];
    /** When this task is a clarifications round spawned from another task,
     *  the task_id of the parent question. Used to merge subsequent Send Backs
     *  into the same task while the round is open (status !== 'completed'). */
    parent_task_id?: string;
}
export type ThreadTaskStatus = 'pending' | 'in_progress' | 'completed' | 'needs_attention';
export interface ThreadMessage {
    message_id: string;
    role: ThreadMessageRole;
    type: ThreadMessageType;
    visibility: 'all' | 'agent_only';
    content_text?: string;
    content_items?: ContentItem[];
    ai_analysis?: AiAnalysisData;
    doc_check?: DocCheckData;
    clarification?: ClarificationData;
    send_back?: SendBackData;
    /** Aggregate resolver verdict — rendered inside the parent send_back panel, not inline. */
    resolution_verdict?: import('../../types/shared_data.js').ResolutionCheck;
    status_change?: {
        from: string;
        to: string;
    };
    /** Set when this message was created via the inline Reply button on a send-back issue card. */
    reply_to?: {
        source_content_id: string;
        file_name?: string;
        rule_name?: string;
    };
    user_name?: string;
    user_id?: string;
    time: string;
}
export type ThreadMessageRole = 'agent' | 'client' | 'system';
export type ThreadMessageType = 'comment' | 'content' | 'status_change' | 'ai_analysis' | 'clarification' | 'doc_check' | 'send_back' | 'resolution_verdict';
export interface SendBackData {
    /** Content ID of the original file */
    source_content_id: string;
    /** File reference for pinned display */
    source_file?: ContentFileRef;
    /** Issues being sent back with agent feedback */
    issues: SendBackIssue[];
    /** Full conversation history for collapsible display */
    history: SendBackHistoryEntry[];
}
export interface SendBackIssue {
    rule_id: string;
    rule_name?: string;
    /** Stable issue id within the rule. For single-issue rules this is '0'. */
    issue_id?: string;
    issue_description: string;
    /** Monetary amount the client must reconcile (carried from the originating ValidationIssue, e.g. "$437.47"). */
    amount?: string;
    /** Date constraint for the issue (carried from the originating ValidationIssue, e.g. "1 July 2024 - 30 June 2025"). */
    date?: string;
    /** Client's original response text */
    client_response?: string;
    /** Client's selected option */
    client_choice?: string;
    /** Agent's feedback on why it's being sent back */
    agent_feedback: string;
    /**
     * When this entry represents a bulk group, child_issues lists the underlying
     * issues being sent back together. Absent for single-issue sends (back-compat).
     */
    child_issues?: Array<{
        issue_id: string;
        issue_description: string;
        date?: string;
        kind?: 'file_issue' | 'missing_file';
        amount?: string;
    }>;
    /** Group category (when child_issues is set) — drives the renderer's category label. */
    category_kind?: 'file_issue' | 'missing_file';
}
export interface SendBackHistoryEntry {
    role: 'system' | 'client' | 'agent';
    action: string;
    message: string;
    time: string;
}
/** Decision the agent recorded on a single validation rule for a file.
 *  Used as the value type of `ContentItem.rule_actions`. */
export type RuleAction = 'accepted' | 'sent_back';
/** One decision the agent records in a batch submitted from the Pending
 *  Review panel. The `comment` is only meaningful when `action === 'sent_back'`. */
export interface RuleDecision {
    rule_id: string;
    action: RuleAction;
    comment?: string;
    rule_result: import('../../types/validation.js').ValidationRuleResult;
}
export interface ContentItem {
    content_id: string;
    type: 'file' | 'text';
    /** For type='file' */
    file?: ContentFileRef;
    /** For type='text' */
    text?: string;
    /** If split from a parent (PDF splitting) */
    parent_content_id?: string;
    split_info?: {
        page_range?: string;
        label?: string;
    };
    /** AI categorization (applied after analysis) */
    category?: string;
    category_label?: string;
    classification_result?: ClassificationResult;
    /** Whether issues have been sent back by agent */
    sent_back?: boolean;
    /** Whether the agent has accepted the client's responses to validation issues
     *  on this item. Set after the agent clicks Accept on the Pending Review panel. */
    accepted?: boolean;
    /** Persisted validation rule results from the pipeline */
    validation_rule_results?: import('../../types/validation.js').ValidationRuleResult[];
    /** Persisted client responses to validation issues */
    issue_responses?: Record<string, {
        response_choice?: string;
        user_comment?: string;
        responded_at?: string;
    }>;
    /** This file replaces another (link to original content_id) */
    replaces_content_id?: string;
    /** This file has been replaced by another (link to replacement content_id) */
    replaced_by_content_id?: string;
    /**
     * ISO timestamp recording when the backoffice validation phase last ran
     * for this file. Unset = not yet run. Used to gate the agent's "Run
     * Backoffice Validations" bulk action so each file only runs once.
     */
    backoffice_validated_at?: string;
    /** Per-rule decision the agent made on this file's validation rules.
     *  Keyed by rule_id. Absence of an entry means the rule is still Pending
     *  (no decision yet, panel will render it for review).
     *  - 'accepted'  → agent accepted the client's response without escalation
     *  - 'sent_back' → agent created a clarifications message for this rule
     *  When this map is populated, the file-level `accepted` / `sent_back`
     *  flags are derived from it (see `compute_file_decision_state`). */
    rule_actions?: Record<string, RuleAction>;
}
/** Per-tag reason emitted by the classifier; preserved for debug/review. */
export interface ClassificationTagReason {
    name: string;
    reason: string;
}
/**
 * Render hint and LLM extraction guidance for a single per-doctype field.
 * Used by both the classification prompt (server) and the inline field
 * renderer (client). Lives here (not in src/lib/) so the renderer can
 * import it without pulling a server-only module into the client bundle.
 */
export type ExpectedFieldType = 'string' | 'number' | 'date' | 'boolean' | 'currency';
export interface ExpectedField {
    /** Snake_case key the LLM must return inside extracted_fields. */
    key: string;
    /** Plain-English description guiding the LLM. */
    description?: string;
    /** Render hint for scalar values. Drives the formatter; falls back to inference if absent.
     *  Ignored when `array_of` is set. */
    type?: ExpectedFieldType;
    /** Display label override. Defaults to prettify_key(key). */
    label?: string;
    /**
     * Declares the value is an array of structured rows (one row per array
     * element). When set, `type` is ignored and the renderer displays the
     * field as a table with one column per shape entry.
     *
     * The LLM is instructed via `render_document_types` to emit this field
     * as a JSON array of objects, each with the listed shape keys.
     */
    array_of?: {
        type: 'object';
        shape: ExpectedField[];
    };
}
/**
 * Doctype descriptor used by both the classification pipeline (server) and
 * the inline renderer (client). Lives here (not in src/lib/) so client code
 * can import it without pulling a server-only module into the client bundle.
 * `src/lib/classification_handler.ts` re-exports this type for back-compat
 * with consumers who import from `hazo_collab_forms/lib`.
 */
export interface ClassificationDocumentType {
    type_id: string;
    type_label: string;
    description?: string;
    /** Optional per-doctype field hints. Renders into the prompt; consumed by the inline renderer. */
    expected_fields?: ExpectedField[];
}
/** Result from document classification LLM call */
export interface ClassificationResult {
    document_type: string;
    tags: string[];
    tag_reasons?: ClassificationTagReason[];
    confidence: number;
    document_date?: string;
    document_nature?: string;
    /**
     * Structured fields lifted out of the document by the same LLM call.
     * Wider than src/types/shared_data.ts ExtractedResponseFields — the
     * classification pipeline passes through arbitrary keys; the resolver
     * still consumes the named four (total/date/vendor/property_address)
     * via shared_data's narrower type.
     */
    extracted_fields?: {
        total?: number;
        date?: string;
        vendor?: string;
        property_address?: string;
        /**
         * Open index signature. The classification pipeline now passes through
         * any keys the LLM returns. Renderer narrows per-key at the call site
         * via expected_fields type hints + value-based inference.
         */
        [key: string]: unknown;
    };
}
export interface ContentFileRef {
    file_id: string;
    file_name: string;
    file_size?: string;
    mime_type?: string;
}
export interface AiAnalysisData {
    items: AiContentResult[];
}
export interface AiContentResult {
    content_ref: string;
    classification?: {
        document_type: string;
        tags: string[];
        confidence: number;
    };
    validation: {
        status: 'passed' | 'issues' | 'error';
        checks: AiCheck[];
    };
    /** PDF splitting: child content items */
    split_items?: ContentItem[];
    /** Text analysis: structured extraction */
    extracted_data?: ExtractedDataGroup[];
    /** Agent action state */
    review_status?: 'pending' | 'accepted' | 'dismissed' | 'sent_to_client';
    sent_message_id?: string;
    /** Agent-edited values (stored alongside originals) */
    edited_data?: ExtractedDataGroup[];
}
export interface AiCheck {
    check_id: string;
    name: string;
    status: 'passed' | 'failed' | 'warning';
    description: string;
    severity: 'error' | 'warning' | 'info';
}
export interface ExtractedDataGroup {
    category: string;
    fields: ExtractedField[];
}
export interface ExtractedField {
    key: string;
    label: string;
    value: string;
    issue?: string;
    severity?: 'error' | 'warning' | 'info';
}
export interface DocCheckData {
    content_ref: string;
    /** Whether this check was on a file or text input */
    source_type?: 'file' | 'text';
    status: 'passed' | 'issues' | 'resolved';
    summary: string;
    issues?: {
        description: string;
        /** The exact text snippet that triggered the issue (for text checks) */
        text_snippet?: string;
    }[];
    /**
     * LLM relevance verdict for the file (set by the aggregate resolver). Drives
     * the per-file relevance pill in FileBar (Matches / Wrong property / Unclear
     * / Off-topic).
     */
    relevance?: 'matches' | 'mismatch' | 'unclear' | 'off_topic';
    /** Short reason addressed to the client, paired with `relevance`. */
    relevance_reason?: string;
}
export interface ClarificationData {
    questions: ClarificationQuestion[];
}
export interface ClarificationQuestion {
    id: string;
    text: string;
    /** Reference to AI issue (if forwarded from AI analysis) */
    ai_ref?: {
        content_ref: string;
        check_id?: string;
        field_key?: string;
    };
    response?: string;
    response_files?: ContentItem[];
    response_time?: string;
    response_by?: string;
}
export interface ThreadFormProps {
    data: ThreadFormData;
    role: 'agent' | 'client';
    current_user: ThreadUser & {
        id: string;
    };
    /**
     * Persistence callback — receives the full ThreadFormData and is intended
     * for debounced backend saves. NOT a state setter: wiring this in isolation
     * will silently drop UI updates from controls that have no dedicated callback
     * (e.g. selection toggles before `on_selection_change` was added). Pair with
     * the per-event setters below or with a `use_thread_form` hook.
     */
    on_form_change?: (data: ThreadFormData) => void;
    /** State setters — call to update local controlled state. */
    on_task_update?: (task: ThreadTask) => void;
    on_message_add?: (task_id: string, msg: ThreadMessage) => void;
    on_message_edit?: (task_id: string, message_id: string, updated: {
        content_text?: string;
        content_items?: ContentItem[];
    }) => void;
    on_message_delete?: (task_id: string, message_id: string) => void;
    /**
     * State setter for collected-data Keep selections. Receives a delta — only
     * the keys that changed (chain-expanded so toggling either end of a
     * replacement chain syncs both ends). The consumer should merge this delta
     * into `data.collected_data_selections`. Wire to `use_thread_form`'s
     * `update_selections` to get the canonical merge behavior.
     */
    on_selection_change?: (selections_delta: Record<string, boolean>) => void;
    /** Agent actions */
    on_send_form?: () => void;
    on_close_form?: () => void;
    on_export_data?: (selected: ContentItem[]) => void;
    /** AI pipeline (consuming app handles actual AI calls) */
    on_request_analysis?: (content: ContentItem[], type: 'front_office' | 'back_office') => void;
    on_request_reanalysis?: (content_id: string) => void;
    /**
     * Per-file re-extract action. When provided AND `role === 'agent'`,
     * `ExtractedFieldsInline` renders an icon + kebab menu in the meta line.
     *
     * `scope`:
     *   - 'classification' — re-runs the classify_document LLM call only.
     *   - 'full' — re-runs classification AND back-office validation.
     *
     * The consumer is expected to call `on_update_content_item` with the
     * new `classification_result` once the API returns.
     *
     * If the function returns a Promise, the renderer awaits it and shows
     * a dim-in-place loading state for the duration.
     */
    on_request_reextraction?: (content_id: string, scope: 'classification' | 'full') => Promise<void> | void;
    /** File handling */
    file_manager?: FileManagerConfig;
    pdf_viewer?: React.ComponentType<any>;
    /** API endpoint for file classification (e.g., '/api/classify') */
    classification_api_url?: string;
    /**
     * Allow-list of document types sent to the classification API. When provided,
     * the LLM must pick a type_id from this list (or 'unknown' if nothing fits).
     * Omit to let the classifier use whatever it finds in the prompt.
     */
    available_document_types?: ClassificationDocumentType[];
    /**
     * Allow-list of classification tags sent to the classification API. When
     * provided, the LLM is restricted to these tag_ids. Sourced from the Tag
     * Editor in the consuming app (hazo_app_config / fb_form / available_tags).
     */
    available_tags?: Array<{
        tag_id: string;
        tag_label: string;
        description?: string;
    }>;
    /** API endpoint for file validation (e.g., '/api/validation') */
    validation_api_url?: string;
    /** API endpoint to fetch validation rules by document_type (e.g., '/api/validation-rules') */
    validation_rules_api_url?: string;
    /**
     * API endpoint for the content gate (e.g., '/api/thread-form/content-gate').
     * When provided, short client-authored text messages are gated through this
     * endpoint before running text validation. Conversational replies like "I
     * don't have it" get filtered out, so no AI-authored issues surface to the
     * client. Omit to skip the gate (validation runs on all text).
     */
    content_gate_api_url?: string;
    /**
     * API endpoint for the aggregate resolver (sum_match, etc.) — typically '/api/resolution'.
     * When provided, client responses to clarifications carrying structured
     * amount/date issues are validated as a set: extracted totals must equal the
     * expected amount within tolerance, and dates must fall within the issue's
     * date range. The verdict is injected as a doc_check message in the thread.
     * Omit to skip aggregate validation entirely.
     */
    resolution_api_url?: string;
    /**
     * API endpoint that extracts structured fields (total/date/vendor) from a
     * receipt-style file. Used by the resolver when client-uploaded response
     * files lack structured data. Wired to use_file_pipeline.extract_response_fields.
     */
    response_extraction_api_url?: string;
    /** Functional update to persist changes to a ContentItem (safe from stale closures) */
    on_update_content_item?: (content_id: string, updates: Partial<ContentItem>) => void;
    /** Activity log callback — called for all significant actions */
    on_log?: (message: string) => void;
    /** Optional features */
    show_json_viewer?: boolean;
    available_templates?: TemplateOption[];
    /** File action rendering — 'icon' (default, eye) or 'text' ("View"). */
    view_button_variant?: 'icon' | 'text';
    /**
     * Override info-icon visibility on file bars. When omitted, defaults to
     * agent-only (true for role='agent', false for role='client'). Set
     * explicitly to force show/hide regardless of role.
     */
    show_info_icon?: boolean;
    /**
     * When true, the Collected Data tab shows each file's
     * classification_result.extracted_fields inline below the file row.
     * Default: false.
     */
    show_extracted_fields?: boolean;
    /**
     * Custom renderer for content beneath each file row in Collected Data.
     * Takes precedence over show_extracted_fields. Use for fully custom layouts.
     */
    render_collected_item_details?: (item: ContentItem) => React.ReactNode;
    /** Locale string for inline field formatting. Default: browser. */
    collected_data_locale?: string;
    /** ISO 4217 currency code for inline field formatting. Default: 'AUD'. */
    collected_data_currency_code?: string;
    /** Truncate threshold for long string values in the inline display. Default: 80. */
    collected_data_truncate_chars?: number;
    /**
     * Form sections to render inside the collapsible Key-Info drawer above the
     * task list. When omitted (and `form_data` is also omitted), the drawer is
     * not rendered and ThreadForm behaves identically to 5.5.0.
     *
     * The drawer always renders the embedded view in `mode="edit"`.
     */
    key_info_sections?: ViewSection[];
    /**
     * Form data backing the Key-Info drawer's embedded view.
     * Should be provided when `key_info_sections` is set; the drawer renders an
     * empty form when omitted.
     */
    key_info_form_data?: Record<string, unknown>;
    /**
     * Persistence callback for form-data changes inside the Key-Info drawer.
     * Wired to the embedded HazoCollabFormView's `on_form_data_change`.
     */
    on_key_info_form_data_change?: (data: Record<string, unknown>) => void;
    /**
     * Per-field metadata passed through to the embedded Key-Info HazoCollabFormView.
     * Keyed by field_id; same shape consumed by HazoCollabFormView.
     *
     * Pairs with `on_metadata_change` for the round-trip.
     */
    field_metadata?: Record<string, FieldMetadataInput>;
    /**
     * Fires when the embedded Key-Info view mutates a field's metadata — e.g.
     * H.7 auto-edit detection transitions `confirm_state` from `'prefilled'`
     * to `'edited'`, or `show_confirm_action`'s ✓ button transitions to
     * `'confirmed'`.
     *
     * NOTE: this does NOT replace `on_form_change` — it complements it. Value
     * changes flow through `on_key_info_form_data_change`; metadata changes
     * flow through here.
     */
    on_metadata_change?: (change: FieldMetadataChange) => void;
    /**
     * Propagated to the embedded Key-Info HazoCollabFormView. When true,
     * fields with `confirm_state: 'prefilled'` show the inline ✓ confirm
     * affordance. Defaults to false.
     */
    show_confirm_action?: boolean;
    /**
     * Header label for the Key-Info drawer. Defaults to 'Key Information'.
     */
    key_info_title?: string;
    /**
     * Initial expanded state of the drawer. Defaults to false (collapsed).
     */
    key_info_default_expanded?: boolean;
    /**
     * Propagated to the embedded Key-Info HazoCollabFormView.
     * See `HazoCollabFormViewProps.field_action_components` for the full TSDoc.
     * Use this to inject per-field action components (audit history, RFI
     * buttons, etc.) into every Key-Info field row.
     */
    field_action_components?: FieldActionComponents;
    /**
     * Propagated to the embedded Key-Info HazoCollabFormView. When `true`
     * the drawer turns on the built-in FieldAudit feature: it records each
     * change to Key-Info `form_data` as a manual audit entry and renders
     * an inline history panel under each field row. See
     * `HazoCollabFormViewProps.enable_field_audit` for the full TSDoc.
     *
     * Intended for the tax-agent side of a workflow; omit on the client
     * portal to hide audit history.
     *
     * @default false
     */
    enable_field_audit?: boolean;
    /**
     * Idle window (ms) before the built-in audit watcher records a `manual`
     * entry. Forwarded to the embedded HazoCollabFormView. See
     * `HazoCollabFormViewProps.audit_debounce_ms`.
     * @default 750
     */
    audit_debounce_ms?: number;
    /**
     * Number of fields to place per row inside the Key-Info drawer.
     *
     * - `1` (default) — single-column layout (original behaviour)
     * - `2` — two fields per row; good for medium-density key-info panels
     * - `3` — three fields per row; compact layout for simple fields
     *
     * Textarea, data-table, and file-upload fields always span the full row
     * regardless of this setting (they carry `force_full_row` internally).
     * Forwarded to the embedded `KeyInfoDrawer` → `HazoCollabFormView`.
     */
    key_info_field_columns?: 1 | 2 | 3;
    /**
     * When true, required Key-Info fields that are empty or have a validation
     * error show a light pink background. Forwarded to the embedded
     * HazoCollabFormView via KeyInfoDrawer. Default: false.
     */
    key_info_highlight_empty_required?: boolean;
    /**
     * Offset added to each task's displayed question number (Q-pill and
     * `aria-label`). Useful when the KeyInfoDrawer occupies Q1 and you want
     * tasks to begin at Q2 — pass `task_number_offset={1}` in that case.
     *
     * `parent_question_number` in send-back references shifts by the same
     * amount automatically, so "From Q{N}" chips remain consistent.
     *
     * @default 0
     */
    task_number_offset?: number;
}
/**
 * Imperative handle exposed by ThreadForm via `forwardRef`. Additive — new
 * methods are appended, existing call sites unaffected when adding methods
 * in future versions.
 */
export interface ThreadFormRef {
    /**
     * Mark every field currently in `confirm_state: 'prefilled'` (in the
     * embedded Key-Info HazoCollabFormView) as `'confirmed'`. Fires
     * `on_metadata_change` once per transitioned field. Returns the field IDs
     * that were transitioned.
     *
     * Returns an empty array when no Key-Info drawer is mounted.
     */
    confirm_all_prefilled(): string[];
}
export interface TemplateOption {
    id: string;
    name: string;
    description?: string;
    tasks: Array<{
        title: string;
        description: string;
    }>;
}
export declare const THREAD_FORM_PROMPT_AREA = "thread_form";
export declare const THREAD_FORM_PROMPT_KEYS: {
    readonly classify_document: "classify_document";
    readonly classify_text: "classify_text";
    readonly validate_document_fo: "validate_document_fo";
    readonly validate_document_bo: "validate_document_bo";
    readonly validate_text: "validate_text";
    readonly extract_text_data: "extract_text_data";
    readonly detect_pdf_splits: "detect_pdf_splits";
    readonly map_to_dataform: "map_to_dataform";
    readonly gate_meaningful_content: "gate_meaningful_content";
    readonly resolve_clarification_relevance: "resolve_clarification_relevance";
};
//# sourceMappingURL=types.d.ts.map