-- +goose Up
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS repos (
    id              TEXT PRIMARY KEY,
    name            TEXT NOT NULL,
    remote_url      TEXT NOT NULL,
    default_branch  TEXT NOT NULL,
    workspace_root  TEXT NOT NULL,
    credential_ref  TEXT,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS workspace_leases (
    id          TEXT PRIMARY KEY,
    repo_id     TEXT NOT NULL REFERENCES repos(id),
    slot        TEXT NOT NULL,
    path        TEXT NOT NULL,
    state       TEXT NOT NULL,
    expires_at  TIMESTAMPTZ,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (repo_id, slot)
);

CREATE TABLE IF NOT EXISTS operations (
    id               TEXT PRIMARY KEY,
    repo_id          TEXT NOT NULL REFERENCES repos(id),
    type             TEXT NOT NULL CHECK (type IN ('clone', 'fetch', 'commit', 'push', 'agent_run')),
    state            TEXT NOT NULL CHECK (state IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
    idempotency_key  TEXT CHECK (idempotency_key IS NULL OR btrim(idempotency_key) <> ''),
    created_by       TEXT NOT NULL CHECK (btrim(created_by) <> ''),
    created_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at       TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE UNIQUE INDEX IF NOT EXISTS ux_operations_idempotency
    ON operations (idempotency_key)
    WHERE idempotency_key IS NOT NULL;

CREATE TABLE IF NOT EXISTS operation_events (
    id            TEXT PRIMARY KEY,
    operation_id  TEXT REFERENCES operations(id),
    type          TEXT NOT NULL,
    subject       TEXT NOT NULL,
    payload       JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
    published_at  TIMESTAMPTZ
);

CREATE INDEX IF NOT EXISTS ix_operation_events_operation_ordering
    ON operation_events (operation_id, created_at, id);

CREATE INDEX IF NOT EXISTS ix_operation_events_pending_ordering
    ON operation_events (created_at, id)
    WHERE published_at IS NULL;

CREATE TABLE IF NOT EXISTS revision_cursors (
    repo_id      TEXT NOT NULL,
    branch       TEXT NOT NULL,
    revision     TEXT NOT NULL,
    observed_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    PRIMARY KEY (repo_id, branch)
);

ALTER TABLE revision_cursors DROP CONSTRAINT IF EXISTS revision_cursors_repo_id_fkey;

CREATE TABLE IF NOT EXISTS branch_watches (
    id          TEXT PRIMARY KEY,
    provider    TEXT NOT NULL,
    repo_id     TEXT NOT NULL,
    branch      TEXT NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (provider, repo_id, branch)
);

CREATE TABLE IF NOT EXISTS provider_deliveries (
    id           TEXT PRIMARY KEY,
    provider     TEXT NOT NULL,
    delivery_id  TEXT NOT NULL,
    dedupe_key   TEXT NOT NULL,
    event_id     TEXT NOT NULL,
    repo_id      TEXT NOT NULL,
    branch       TEXT NOT NULL,
    revision     TEXT NOT NULL,
    created_at   TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (provider, dedupe_key)
);

CREATE TABLE IF NOT EXISTS provider_configs (
    id              TEXT PRIMARY KEY,
    endpoint        TEXT NOT NULL CHECK (btrim(endpoint) <> ''),
    credential_ref  TEXT,
    capabilities    BIGINT NOT NULL CHECK (capabilities >= 0),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS agent_run_inputs (
    operation_id      TEXT PRIMARY KEY REFERENCES operations(id),
    repo_id           TEXT NOT NULL CHECK (btrim(repo_id) <> ''),
    branch            TEXT NOT NULL CHECK (btrim(branch) <> ''),
    workspace_path    TEXT NOT NULL CHECK (btrim(workspace_path) <> ''),
    instruction       TEXT NOT NULL CHECK (btrim(instruction) <> ''),
    policy_context    JSONB NOT NULL DEFAULT '{}',
    expected_revision TEXT NOT NULL CHECK (btrim(expected_revision) <> ''),
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS webhook_deliveries (
    id               TEXT PRIMARY KEY,
    event_id         TEXT NOT NULL,
    subscription_id  TEXT NOT NULL,
    status           TEXT NOT NULL CHECK (status IN ('pending', 'sending', 'succeeded', 'retryable', 'failed')),
    attempt_count    INTEGER NOT NULL DEFAULT 0,
    next_attempt_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    last_status_code INTEGER NOT NULL DEFAULT 0,
    last_error       TEXT NOT NULL DEFAULT '',
    created_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (event_id, subscription_id)
);

CREATE INDEX IF NOT EXISTS ix_webhook_deliveries_pending
    ON webhook_deliveries (next_attempt_at, status)
    WHERE status IN ('pending', 'retryable');
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS provider_configs;
DROP TABLE IF EXISTS webhook_deliveries;
DROP TABLE IF EXISTS agent_run_inputs;
DROP TABLE IF EXISTS provider_deliveries;
DROP TABLE IF EXISTS branch_watches;
DROP TABLE IF EXISTS revision_cursors;
DROP TABLE IF EXISTS operation_events;
DROP TABLE IF EXISTS operations;
DROP TABLE IF EXISTS workspace_leases;
DROP TABLE IF EXISTS repos;
-- +goose StatementEnd
