-- ══════════════════════════════════════════════════════════════════════════════
-- AGENTE AI — Schema Supabase completo
-- Incolla questo file nel SQL Editor: Dashboard → SQL Editor → New query → Run
-- Tutti gli statement sono idempotenti (IF NOT EXISTS / CREATE OR REPLACE).
-- ══════════════════════════════════════════════════════════════════════════════


-- ── 0. Estensioni ─────────────────────────────────────────────────────────────
CREATE EXTENSION IF NOT EXISTS vector;


-- ══════════════════════════════════════════════════════════════════════════════
-- 1. MEMORIA EPISODICA — tabella episodes
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.episodes (
    id      BIGSERIAL   PRIMARY KEY,
    type    TEXT        NOT NULL,
    task    TEXT        NOT NULL,
    output  TEXT,
    success INTEGER     DEFAULT 1,
    ts      TEXT        NOT NULL,
    tags    TEXT        DEFAULT '[]'
);

CREATE INDEX IF NOT EXISTS idx_episodes_type ON public.episodes (type);
CREATE INDEX IF NOT EXISTS idx_episodes_ts   ON public.episodes (ts);

ALTER TABLE public.episodes ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='episodes' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.episodes FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;


-- ══════════════════════════════════════════════════════════════════════════════
-- 2. MEMORIA SEMANTICA — tabella semantic_memory + pgvector
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.semantic_memory (
    id        TEXT    PRIMARY KEY,
    content   TEXT    NOT NULL,
    metadata  JSONB   DEFAULT '{}'
);

ALTER TABLE public.semantic_memory
    ADD COLUMN IF NOT EXISTS embedding vector(384);

ALTER TABLE public.semantic_memory ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='semantic_memory' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.semantic_memory FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;

CREATE OR REPLACE FUNCTION match_semantic_memory(
    query_embedding vector(384),
    match_count     int   DEFAULT 5,
    match_threshold float DEFAULT 0.2
)
RETURNS TABLE (id text, content text, metadata jsonb, similarity float)
LANGUAGE sql STABLE AS $$
    SELECT id, content, metadata,
           (1 - (embedding <=> query_embedding))::float AS similarity
    FROM public.semantic_memory
    WHERE embedding IS NOT NULL
      AND (1 - (embedding <=> query_embedding)) > match_threshold
    ORDER BY embedding <=> query_embedding
    LIMIT match_count;
$$;


-- ══════════════════════════════════════════════════════════════════════════════
-- 3. MEMORIA AGENTE — tabella agent_memory (incident registry + decision memory)
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.agent_memory (
    key        TEXT        PRIMARY KEY,
    value      TEXT        NOT NULL DEFAULT '{}',
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

ALTER TABLE public.agent_memory ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='agent_memory' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.agent_memory FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;


-- ══════════════════════════════════════════════════════════════════════════════
-- 4. TASK AGENTE — tabelle agent_tasks + agent_task_events
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.agent_tasks (
    task_id     TEXT    PRIMARY KEY,
    goal        TEXT    NOT NULL,
    status      TEXT    NOT NULL DEFAULT 'QUEUED',
    max_steps   INTEGER NOT NULL DEFAULT 8,
    context     TEXT    NOT NULL DEFAULT '[]',
    created_at  BIGINT  NOT NULL DEFAULT 0,
    updated_at  BIGINT  NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS public.agent_task_events (
    id           BIGSERIAL PRIMARY KEY,
    task_id      TEXT      NOT NULL REFERENCES public.agent_tasks(task_id) ON DELETE CASCADE,
    event_index  INTEGER   NOT NULL,
    event_data   TEXT      NOT NULL,
    created_at   BIGINT    NOT NULL DEFAULT 0,
    UNIQUE (task_id, event_index)
);

CREATE INDEX IF NOT EXISTS idx_agent_task_events_lookup
    ON public.agent_task_events (task_id, event_index ASC);

ALTER TABLE public.agent_tasks       ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.agent_task_events ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='agent_tasks' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.agent_tasks       FOR ALL TO anon USING (true) WITH CHECK (true);
    CREATE POLICY "anon full access" ON public.agent_task_events FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;

CREATE OR REPLACE FUNCTION purge_old_agent_tasks() RETURNS void
LANGUAGE plpgsql AS $$
DECLARE cutoff BIGINT := (EXTRACT(EPOCH FROM NOW()) * 1000 - 7 * 86400000)::BIGINT;
BEGIN DELETE FROM public.agent_tasks WHERE updated_at < cutoff; END;
$$;


-- ══════════════════════════════════════════════════════════════════════════════
-- 5. SKILL TRACKER — tabelle skill_stats + skill_patterns
-- ══════════════════════════════════════════════════════════════════════════════
CREATE OR REPLACE FUNCTION _touch_updated_at()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN NEW.updated_at = now(); RETURN NEW; END;
$$;

CREATE TABLE IF NOT EXISTS public.skill_stats (
    session_id       TEXT             NOT NULL,
    tool_name        TEXT             NOT NULL,
    success_count    INTEGER          NOT NULL DEFAULT 0,
    fail_count       INTEGER          NOT NULL DEFAULT 0,
    last_used        DOUBLE PRECISION NOT NULL DEFAULT 0,
    total_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
    updated_at       TIMESTAMPTZ      NOT NULL DEFAULT now(),
    PRIMARY KEY (session_id, tool_name)
);

CREATE INDEX IF NOT EXISTS idx_skill_stats_session ON public.skill_stats (session_id);
ALTER TABLE public.skill_stats ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='skill_stats' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.skill_stats FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;
DROP TRIGGER IF EXISTS trg_skill_stats_updated_at ON public.skill_stats;
CREATE TRIGGER trg_skill_stats_updated_at BEFORE UPDATE ON public.skill_stats
    FOR EACH ROW EXECUTE FUNCTION _touch_updated_at();

CREATE TABLE IF NOT EXISTS public.skill_patterns (
    id             TEXT             PRIMARY KEY,
    task_signature TEXT             NOT NULL,
    tool_sequence  TEXT[]           NOT NULL,
    success_count  INTEGER          NOT NULL DEFAULT 0,
    total_count    INTEGER          NOT NULL DEFAULT 0,
    last_used      BIGINT           NOT NULL DEFAULT 0,
    confidence     DOUBLE PRECISION NOT NULL DEFAULT 0,
    updated_at     TIMESTAMPTZ      NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_skill_patterns_confidence ON public.skill_patterns (confidence DESC);
CREATE INDEX IF NOT EXISTS idx_skill_patterns_last_used  ON public.skill_patterns (last_used  DESC);
ALTER TABLE public.skill_patterns ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='skill_patterns' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.skill_patterns FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;
DROP TRIGGER IF EXISTS trg_skill_patterns_updated_at ON public.skill_patterns;
CREATE TRIGGER trg_skill_patterns_updated_at BEFORE UPDATE ON public.skill_patterns
    FOR EACH ROW EXECUTE FUNCTION _touch_updated_at();


-- ══════════════════════════════════════════════════════════════════════════════
-- 6. FILE SYSTEM VIRTUALE — tabella vfs_files
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.vfs_files (
    id         TEXT        PRIMARY KEY,
    path       TEXT        NOT NULL,
    content    TEXT        NOT NULL DEFAULT '',
    mime_type  TEXT        NOT NULL DEFAULT 'text/plain',
    size       BIGINT      NOT NULL DEFAULT 0,
    created_at BIGINT      NOT NULL DEFAULT 0,
    updated_at BIGINT      NOT NULL DEFAULT 0
);

ALTER TABLE public.vfs_files ADD COLUMN IF NOT EXISTS version BIGINT NOT NULL DEFAULT 0;

CREATE INDEX IF NOT EXISTS idx_vfs_files_path    ON public.vfs_files (path);
CREATE INDEX IF NOT EXISTS vfs_files_version_idx ON public.vfs_files (id, version);

ALTER TABLE public.vfs_files ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='vfs_files' AND policyname='anon full access') THEN
    CREATE POLICY "anon full access" ON public.vfs_files FOR ALL TO anon USING (true) WITH CHECK (true);
  END IF;
END $$;

CREATE OR REPLACE FUNCTION public._vfs_bump_version()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN NEW.version = OLD.version + 1; RETURN NEW; END;
$$;
DROP TRIGGER IF EXISTS trg_vfs_version ON public.vfs_files;
CREATE TRIGGER trg_vfs_version BEFORE UPDATE ON public.vfs_files
    FOR EACH ROW EXECUTE FUNCTION public._vfs_bump_version();


-- ══════════════════════════════════════════════════════════════════════════════
-- 7. TOKEN OAUTH — tabelle managed_tokens + oauth_states
-- ══════════════════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS public.managed_tokens (
    user_id       TEXT   NOT NULL DEFAULT 'default',
    provider      TEXT   NOT NULL,
    access_token  TEXT   NOT NULL DEFAULT '',
    refresh_token TEXT   NOT NULL DEFAULT '',
    expires_at    BIGINT NOT NULL DEFAULT 0,
    scope         TEXT   NOT NULL DEFAULT '',
    raw_meta      TEXT   NOT NULL DEFAULT '{}',
    created_at    BIGINT NOT NULL DEFAULT 0,
    updated_at    BIGINT NOT NULL DEFAULT 0,
    UNIQUE (user_id, provider)
);

CREATE INDEX IF NOT EXISTS managed_tokens_user_idx ON public.managed_tokens (user_id, provider);
ALTER TABLE public.managed_tokens ENABLE ROW LEVEL SECURITY;
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='managed_tokens' AND policyname='service only') THEN
    CREATE POLICY "service only" ON public.managed_tokens FOR ALL TO service_role USING (true) WITH CHECK (true);
  END IF;
END $$;

CREATE TABLE IF NOT EXISTS public.oauth_states (
    state      TEXT   PRIMARY KEY,
    provider   TEXT   NOT NULL,
    user_id    TEXT   NOT NULL DEFAULT 'default',
    created_at BIGINT NOT NULL DEFAULT 0
);

CREATE OR REPLACE FUNCTION public._purge_oauth_states() RETURNS void
LANGUAGE plpgsql AS $$
BEGIN
    DELETE FROM public.oauth_states
    WHERE created_at < (EXTRACT(EPOCH FROM NOW()) * 1000 - 600000)::BIGINT;
END;
$$;


-- ══════════════════════════════════════════════════════════════════════════════
-- FINE — Verifica eseguendo:
--   SELECT table_name FROM information_schema.tables
--   WHERE table_schema = 'public' ORDER BY table_name;
-- ══════════════════════════════════════════════════════════════════════════════
