-- Spore Agent Commons — Core Primitives
-- Claims, Evidence, Attestations, Intents, Commitments

-- ============================================================
-- Claims (knowledge claims in the commons)
-- ============================================================
CREATE TABLE IF NOT EXISTS claims (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    rid TEXT UNIQUE NOT NULL,
    proposer_rid TEXT NOT NULL,
    content TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'proposed'
        CHECK (status IN ('proposed', 'supported', 'challenged', 'superseded')),
    confidence FLOAT DEFAULT 0.5,
    anchor_type TEXT DEFAULT 'assertion',
    embedding vector(1024),
    metadata JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_claims_proposer ON claims (proposer_rid);
CREATE INDEX IF NOT EXISTS idx_claims_status ON claims (status);
CREATE INDEX IF NOT EXISTS idx_claims_metadata ON claims USING GIN (metadata);

-- ============================================================
-- Evidence (supports or challenges a claim)
-- ============================================================
CREATE TABLE IF NOT EXISTS evidence (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    rid TEXT UNIQUE NOT NULL,
    claim_id UUID NOT NULL REFERENCES claims(id) ON DELETE CASCADE,
    relation TEXT NOT NULL CHECK (relation IN ('supports', 'challenges')),
    body TEXT NOT NULL,
    provenance JSONB NOT NULL DEFAULT '{}',
    embedding vector(1024),
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_evidence_claim ON evidence (claim_id);
CREATE INDEX IF NOT EXISTS idx_evidence_relation ON evidence (relation);

-- ============================================================
-- Attestations (endorse/dispute/abstain on a claim)
-- ============================================================
CREATE TABLE IF NOT EXISTS attestations (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    rid TEXT UNIQUE NOT NULL,
    claim_id UUID NOT NULL REFERENCES claims(id) ON DELETE CASCADE,
    attester_rid TEXT NOT NULL,
    verdict TEXT NOT NULL CHECK (verdict IN ('endorse', 'dispute', 'abstain')),
    strength FLOAT NOT NULL DEFAULT 1.0,
    reasoning TEXT DEFAULT '',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (claim_id, attester_rid)
);

CREATE INDEX IF NOT EXISTS idx_attestations_claim ON attestations (claim_id);
CREATE INDEX IF NOT EXISTS idx_attestations_attester ON attestations (attester_rid);

-- ============================================================
-- Claim strength (materialized view)
-- ============================================================
CREATE MATERIALIZED VIEW IF NOT EXISTS claim_strength AS
SELECT
    c.id AS claim_id,
    c.rid AS claim_rid,
    c.status,
    c.confidence,
    COUNT(DISTINCT CASE WHEN a.verdict = 'endorse' THEN a.id END) AS endorse_count,
    COUNT(DISTINCT CASE WHEN a.verdict = 'dispute' THEN a.id END) AS dispute_count,
    COUNT(DISTINCT CASE WHEN a.verdict = 'abstain' THEN a.id END) AS abstain_count,
    COUNT(DISTINCT CASE WHEN e.relation = 'supports' THEN e.id END) AS supporting_evidence,
    COUNT(DISTINCT CASE WHEN e.relation = 'challenges' THEN e.id END) AS challenging_evidence,
    COALESCE(
        (COUNT(DISTINCT CASE WHEN a.verdict = 'endorse' THEN a.id END)::float -
         COUNT(DISTINCT CASE WHEN a.verdict = 'dispute' THEN a.id END)::float) /
        NULLIF(COUNT(DISTINCT a.id)::float, 0),
        0
    ) AS net_sentiment,
    GREATEST(
        MAX(a.created_at),
        MAX(e.created_at),
        c.created_at
    ) AS last_activity
FROM claims c
LEFT JOIN attestations a ON a.claim_id = c.id
LEFT JOIN evidence e ON e.claim_id = c.id
GROUP BY c.id, c.rid, c.status, c.confidence;

CREATE UNIQUE INDEX IF NOT EXISTS idx_claim_strength_id ON claim_strength (claim_id);

-- ============================================================
-- Intents (need/offer/possibility)
-- ============================================================
CREATE TABLE IF NOT EXISTS intents (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    rid TEXT UNIQUE NOT NULL,
    publisher_rid TEXT NOT NULL,
    title TEXT NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    intent_type TEXT NOT NULL CHECK (intent_type IN ('need', 'offer', 'possibility')),
    capacity JSONB NOT NULL DEFAULT '{}',
    timing JSONB NOT NULL DEFAULT '{}',
    governance_fit TEXT[] DEFAULT '{}',
    state TEXT NOT NULL DEFAULT 'open'
        CHECK (state IN ('open', 'matched', 'committed', 'expired', 'withdrawn')),
    embedding vector(1024),
    metadata JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_intents_publisher ON intents (publisher_rid);
CREATE INDEX IF NOT EXISTS idx_intents_type ON intents (intent_type);
CREATE INDEX IF NOT EXISTS idx_intents_state ON intents (state);

-- ============================================================
-- Intent matches (computed similarity pairs)
-- ============================================================
CREATE TABLE IF NOT EXISTS intent_matches (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    intent_a_id UUID NOT NULL REFERENCES intents(id) ON DELETE CASCADE,
    intent_b_id UUID NOT NULL REFERENCES intents(id) ON DELETE CASCADE,
    similarity FLOAT NOT NULL,
    match_details JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (intent_a_id, intent_b_id),
    CHECK (intent_a_id < intent_b_id)
);

CREATE INDEX IF NOT EXISTS idx_intent_matches_a ON intent_matches (intent_a_id);
CREATE INDEX IF NOT EXISTS idx_intent_matches_b ON intent_matches (intent_b_id);

-- ============================================================
-- Commitments (lifecycle state machine)
-- ============================================================
CREATE TABLE IF NOT EXISTS commitments (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    rid TEXT UNIQUE NOT NULL,
    title TEXT NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    state TEXT NOT NULL DEFAULT 'proposed'
        CHECK (state IN ('proposed', 'verified', 'active', 'evidence_linked',
                         'redeemed', 'disputed', 'resolved', 'cancelled')),
    proposer_rid TEXT NOT NULL,
    acceptor_rid TEXT,
    settlement_type TEXT DEFAULT 'attestation',
    terms JSONB NOT NULL DEFAULT '{}',
    metadata JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_commitments_state ON commitments (state);
CREATE INDEX IF NOT EXISTS idx_commitments_proposer ON commitments (proposer_rid);
CREATE INDEX IF NOT EXISTS idx_commitments_acceptor ON commitments (acceptor_rid);

-- ============================================================
-- Commitment-Evidence links
-- ============================================================
CREATE TABLE IF NOT EXISTS commitment_evidence (
    commitment_id UUID NOT NULL REFERENCES commitments(id) ON DELETE CASCADE,
    evidence_id UUID NOT NULL REFERENCES evidence(id) ON DELETE CASCADE,
    linked_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    PRIMARY KEY (commitment_id, evidence_id)
);
