import { z } from "zod/v4";
import { ConfigEtag, ContentHash, EffectiveWorkerStatus, EffectiveDirectorStatus, IanaTimezone, ProcessStatus, ProxyProtocol, RuntimeStatus, SocialPlatform, Uuid, } from "./domain.js";
import { IdentityRow } from "./identities.js";
/**
 * REST contracts for the Web-UI /workers/:id detail surface (wave 1 Agent B).
 *
 * Split out from rest-contracts.ts to keep the existing wire surface stable
 * while the dp-worker detail tabs land; everything here is browser-facing and
 * never reaches the dp-worker or dp-director.
 */
/* ============================================================================
 * dp-worker create / detail
 * ============================================================================ */
/**
 * Body for POST /api/workers. The api_key may be supplied by the caller (64
 * lowercase hex chars — 32 crypto-random bytes) or omitted to have the
 * server generate one. The column is stored plaintext per v2.13, so the
 * operator can read or reset it later from the dp-worker detail surface.
 */
export const WorkerCreateRequestSchema = z.object({
    name: z.string().min(1).max(120),
    director_id: Uuid.optional(),
    llm_profile_id: Uuid,
    proxy_id: Uuid.optional(),
    identity_id: Uuid.nullable().optional(),
    /** Pre-generated 64-char hex api_key from the UI. Server generates one if absent. */
    api_key: z
        .string()
        .regex(/^[0-9a-f]{64}$/, "api_key must be 64 lowercase hex chars")
        .optional(),
    telegram_bot_token: z.string().min(1).optional(),
    telegram_allowed_users: z.array(z.number().int()).optional(),
    headless: z.boolean().optional(),
    browser_automation_mode: z.enum(["chrome", "cloakbrowser"]).optional(),
});
/** The plaintext api_key wire shape returned after create. */
export const WorkerCreateResponseSchema = z.object({
    id: Uuid,
    name: z.string(),
    api_key: z.string().min(1),
    config_etag: ConfigEtag,
});
const ProxyJoinSchema = z.object({
    id: Uuid,
    label: z.string(),
    protocol: ProxyProtocol,
    host: z.string(),
    port: z.number().int().positive(),
    username: z.string(),
    timezone: IanaTimezone,
});
const LlmProfileJoinSchema = z.object({
    id: Uuid,
    name: z.string(),
    model: z.string(),
});
const DirectorJoinSchema = z.object({
    id: Uuid,
    name: z.string(),
    host_label: z.string(),
    status: EffectiveDirectorStatus,
});
const SessionHeadSchema = z.object({
    id: Uuid,
    content_hash: ContentHash,
    size_bytes: z.number().int().positive(),
    uploaded_at: z.string().datetime(),
    uploaded_by: Uuid,
    r2_object_key: z.string(),
});
export const WorkerDetailResponseSchema = z.object({
    id: Uuid,
    name: z.string(),
    director_id: Uuid.optional(),
    director: DirectorJoinSchema.optional(),
    status: EffectiveWorkerStatus,
    process_status: ProcessStatus.optional(),
    runtime_status: RuntimeStatus.optional(),
    process_observed_at: z.string().datetime().optional(),
    runtime_observed_at: z.string().datetime().optional(),
    last_heartbeat_at: z.string().datetime().optional(),
    effective_status: EffectiveWorkerStatus.optional(),
    current_task_id: Uuid.optional(),
    config_etag: ConfigEtag,
    headless: z.boolean(),
    browser_automation_mode: z.enum(["chrome", "cloakbrowser"]).default("chrome"),
    identity_id: Uuid.nullable().optional(),
    telegram_bot_token: z.string().nullable(),
    telegram_allowed_users: z.array(z.number().int()).optional(),
    created_at: z.string().datetime(),
    updated_at: z.string().datetime(),
    proxy: ProxyJoinSchema.optional(),
    llm_profile: LlmProfileJoinSchema,
    social_accounts_count: z.number().int().nonnegative(),
    scheduled_tasks_count: z.number().int().nonnegative(),
    current_session: SessionHeadSchema.optional(),
    /**
     * Plaintext dp-worker api_key. Surfaced read-only on the detail page so the
     * operator can copy it into an dp-director spawn command or re-paste during
     * fleet migration. Per v2.13 (internal-use stance,
     * feedback_security_simple memory) the key is stored plaintext in
     * `dp_workers.api_key`, so re-displaying it carries no
     * additional disclosure risk.
     */
    api_key: z.string().min(1),
    /**
     * Full identity row when the dp-worker is bound to an identity; null otherwise.
     * Populated via LEFT JOIN in getWorkerDetail (M3.T2).
     */
    identity: IdentityRow.nullable().optional(),
});
/* ============================================================================
 * Social accounts CRUD
 * ============================================================================ */
/**
 * Sub-account model:
 *   - One row per (identity, platform) — enforced by UNIQUE.
 *   - UI restricts to platform ∈ {x, youtube, reddit}; the DB enum stays
 *     wider for backward compat but the API rejects others.
 *   - login_type='password' carries email + optional username (handle) +
 *     password; login_type='oauth' carries no secrets (assumed pre-logged-in
 *     in the Chrome profile).
 *   - persona_text=null means "inherit from identity.persona_text". The
 *     bootstrap composer resolves this before handing config to dp-worker.
 */
const SubAccountPlatform = z.enum(["x", "youtube", "reddit"]);
export const SocialAccountBodySchema = z.object({
    platform: SubAccountPlatform,
    profile_name: z.string().min(1).max(120),
    login_type: z.enum(["password", "oauth"]),
    username: z.string().min(1).max(120).optional(),
    email: z.string().email().optional(),
    password: z.string().min(1).optional(),
    /** Omit / null → inherit identity persona. */
    persona_text: z.string().max(4000).nullable().optional(),
    persona_other_json: z.record(z.string(), z.unknown()).optional(),
    enabled: z.boolean().default(true),
});
export const SocialAccountPatchSchema = z
    .object({
    profile_name: z.string().min(1).max(120).optional(),
    login_type: z.enum(["password", "oauth"]).optional(),
    username: z.string().min(1).max(120).nullable().optional(),
    email: z.string().email().nullable().optional(),
    password: z.string().min(1).nullable().optional(),
    persona_text: z.string().max(4000).nullable().optional(),
    persona_other_json: z.record(z.string(), z.unknown()).nullable().optional(),
    enabled: z.boolean().optional(),
})
    .refine((v) => Object.keys(v).length > 0, {
    message: "patch body must contain at least one field",
});
export const SocialAccountResponseSchema = z.object({
    id: Uuid,
    identity_id: Uuid,
    platform: SocialPlatform,
    profile_name: z.string(),
    login_type: z.enum(["password", "oauth"]),
    username: z.string().nullable(),
    email: z.string().nullable(),
    password: z.string().nullable(),
    persona_text: z.string().nullable(),
    persona_other_json: z.record(z.string(), z.unknown()).optional(),
    enabled: z.boolean(),
    created_at: z.string().datetime(),
    updated_at: z.string().datetime(),
});
/* ============================================================================
 * Chrome sessions history list
 *
 * GET /api/workers/:id/sessions returns past chrome_sessions newest-first with
 * opaque cursor pagination, mirroring the `task-history.ts` shape. The
 * `is_current` flag is true for the single row whose content_hash matches
 * `dp_workers.session_content_hash` — the SessionTab uses it to render
 * a "current" badge without a second round-trip to /api/workers/:id detail.
 *
 * Named `ChromeSessionListRow*` to avoid a name collision with the
 * existing `ChromeSessionRow` postgres-row schema in `db-rows.ts` — they
 * describe different surfaces (DB row vs. browser-facing list row + flag).
 * ============================================================================ */
export const ChromeSessionListRowSchema = z.object({
    id: Uuid,
    content_hash: ContentHash,
    size_bytes: z.number().int().positive(),
    uploaded_at: z.string().datetime(),
    uploaded_by: Uuid,
    r2_object_key: z.string(),
    note: z.string().optional(),
    is_current: z.boolean(),
});
export const ListChromeSessionsResponseSchema = z.object({
    items: z.array(ChromeSessionListRowSchema),
    next_cursor: z.string().nullable(),
});
//# sourceMappingURL=worker-detail-contracts.js.map