-- M8 P3: PostgreSQL-backed scheduled task definitions and durable execution queue.

CREATE TABLE IF NOT EXISTS gateway.scheduled_tasks (
    id uuid PRIMARY KEY,
    code text NOT NULL UNIQUE CHECK (code ~ '^[a-z][a-z0-9_-]{1,63}$'),
    name text NOT NULL CHECK (length(name) BETWEEN 1 AND 128),
    description text NOT NULL DEFAULT '' CHECK (length(description) <= 4000),
    cron_expression text NOT NULL CHECK (length(cron_expression) <= 128),
    timezone text NOT NULL DEFAULT 'UTC' CHECK (length(timezone) <= 128),
    target_type text NOT NULL CHECK (target_type IN ('application', 'digital_employee')),
    target_code text NOT NULL CHECK (length(target_code) BETWEEN 1 AND 64),
    prompt text NOT NULL CHECK (length(prompt) BETWEEN 1 AND 100000),
    variables jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(variables) = 'object'),
    skill_ids uuid[] NOT NULL DEFAULT '{}',
    mcp_server_ids uuid[] NOT NULL DEFAULT '{}',
    conversation_id text NOT NULL DEFAULT '' CHECK (length(conversation_id) <= 128),
    notification_channel_id uuid REFERENCES gateway.notification_channels(id) ON DELETE SET NULL,
    encrypted_api_key bytea NOT NULL,
    api_key_kek_version integer NOT NULL CHECK (api_key_kek_version > 0),
    enabled boolean NOT NULL DEFAULT false,
    next_run_at timestamptz,
    last_run_at timestamptz,
    last_status text NOT NULL DEFAULT '' CHECK (last_status IN ('', 'success', 'failed')),
    last_error text NOT NULL DEFAULT '' CHECK (length(last_error) <= 4000),
    created_by uuid NOT NULL REFERENCES gateway.admin_accounts(id),
    revision bigint NOT NULL DEFAULT 1,
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    CHECK ((enabled AND next_run_at IS NOT NULL) OR (NOT enabled))
);

CREATE INDEX IF NOT EXISTS scheduled_tasks_due_idx
    ON gateway.scheduled_tasks (next_run_at, id) WHERE enabled;

CREATE TABLE IF NOT EXISTS gateway.scheduled_task_runs (
    id uuid PRIMARY KEY,
    task_id uuid NOT NULL REFERENCES gateway.scheduled_tasks(id) ON DELETE CASCADE,
    trigger_type text NOT NULL CHECK (trigger_type IN ('scheduled', 'manual')),
    scheduled_for timestamptz NOT NULL,
    status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running', 'success', 'failed')),
    attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),
    worker_id text NOT NULL DEFAULT '' CHECK (length(worker_id) <= 128),
    started_at timestamptz,
    finished_at timestamptz,
    response jsonb,
    error text NOT NULL DEFAULT '' CHECK (length(error) <= 4000),
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    UNIQUE (task_id, trigger_type, scheduled_for)
);

CREATE INDEX IF NOT EXISTS scheduled_task_runs_pending_idx
    ON gateway.scheduled_task_runs (created_at, id) WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS scheduled_task_runs_history_idx
    ON gateway.scheduled_task_runs (task_id, created_at DESC);
CREATE INDEX IF NOT EXISTS scheduled_task_runs_running_idx
    ON gateway.scheduled_task_runs (started_at) WHERE status = 'running';
