-- ═══════════════════════════════════════════════════════════════════
-- Al Moasis (المؤسس) — Canonical Database Schema
-- ═══════════════════════════════════════════════════════════════════
-- Idempotent. Copy-paste into Supabase SQL Editor for a fresh project,
-- or run against an existing one to add anything missing. CREATE TABLE
-- IF NOT EXISTS / CREATE INDEX IF NOT EXISTS everywhere — safe to re-run.
--
-- This consolidates:
--   src/db/migrate.ts                          (core: tenants/customers/messages/usage/documents/document_chunks)
--   src/db/migrations/002_billing.sql          (platform billing: invoices/budget_config)
--   src/db/migrations/004-add-cron-...         (cron_jobs/cron_executions/sessions/session_messages/approval_requests)
--   src/db/migrations/005-add-customer-memories
--   src/db/migrations/006-add-zatca-invoices
-- ═══════════════════════════════════════════════════════════════════

-- ─── Extensions ──────────────────────────────────────────────────────
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pg_trgm;

-- ═══════════════════════════════════════════════════════════════════
-- CORE TABLES
-- ═══════════════════════════════════════════════════════════════════

CREATE TABLE IF NOT EXISTS tenants (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  owner_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
  business_name TEXT NOT NULL,
  business_name_ar TEXT,
  agent_name TEXT NOT NULL DEFAULT 'مساعد',
  agent_persona TEXT,
  whatsapp_phone TEXT,
  whatsapp_phone_number_id TEXT,
  workspace_path TEXT,
  language TEXT NOT NULL DEFAULT 'ar',
  timezone TEXT NOT NULL DEFAULT 'Asia/Riyadh',
  working_hours JSONB DEFAULT '{"start": "09:00", "end": "17:00", "days": [0,1,2,3,4]}'::jsonb,
  plan TEXT NOT NULL DEFAULT 'free',
  status TEXT NOT NULL DEFAULT 'active',
  owner_name TEXT,
  owner_phone TEXT,
  owner_email TEXT,
  metadata JSONB DEFAULT '{}'::jsonb,    -- holds vat_number, cr_number, custom flags
  settings JSONB DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- For installs that ran the older migrate.ts (which only defined `settings`),
-- ensure `metadata` exists. The ZATCA invoice issuer reads vat_number / cr_number
-- from tenants.metadata and will refuse to issue without it.
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS metadata JSONB DEFAULT '{}'::jsonb;
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS settings JSONB DEFAULT '{}'::jsonb;
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS owner_id UUID REFERENCES auth.users(id) ON DELETE SET NULL;

CREATE TABLE IF NOT EXISTS customers (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  phone TEXT NOT NULL,
  name TEXT,
  language TEXT DEFAULT 'ar',
  dialect TEXT,
  tags TEXT[] DEFAULT '{}',
  first_contact TIMESTAMPTZ NOT NULL DEFAULT now(),
  last_contact TIMESTAMPTZ NOT NULL DEFAULT now(),
  total_messages INT NOT NULL DEFAULT 0,
  status TEXT NOT NULL DEFAULT 'active',
  metadata JSONB DEFAULT '{}'::jsonb,
  UNIQUE(tenant_id, phone)
);

CREATE TABLE IF NOT EXISTS messages (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  customer_id UUID NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
  session_id UUID,
  direction TEXT NOT NULL CHECK (direction IN ('inbound', 'outbound')),
  type TEXT NOT NULL DEFAULT 'text'
    CHECK (type IN ('text','image','audio','video','document','location','sticker','reaction')),
  content TEXT,
  media_url TEXT,
  transcript TEXT,
  model_used TEXT,
  tokens_input INT DEFAULT 0,
  tokens_output INT DEFAULT 0,
  cost_usd DECIMAL(10, 6) DEFAULT 0,
  response_time_ms INT,
  delivery_status TEXT DEFAULT 'sent'
    CHECK (delivery_status IN ('sent', 'delivered', 'read', 'failed')),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS usage (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  date DATE NOT NULL,
  messages_count INT NOT NULL DEFAULT 0,
  tokens_input BIGINT NOT NULL DEFAULT 0,
  tokens_output BIGINT NOT NULL DEFAULT 0,
  cost_usd DECIMAL(12, 6) NOT NULL DEFAULT 0,
  customers_new INT NOT NULL DEFAULT 0,
  customers_active INT NOT NULL DEFAULT 0,
  UNIQUE(tenant_id, date)
);

CREATE TABLE IF NOT EXISTS documents (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  filename TEXT NOT NULL,
  file_path TEXT NOT NULL,
  file_type TEXT NOT NULL,
  chunk_count INT DEFAULT 0,
  status TEXT NOT NULL DEFAULT 'pending'
    CHECK (status IN ('pending','processing','ready','error')),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS document_chunks (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  content TEXT NOT NULL,
  embedding VECTOR(1536),
  metadata JSONB DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- ═══════════════════════════════════════════════════════════════════
-- BILLING (platform charges its tenants — NOT ZATCA invoices to end users)
-- ═══════════════════════════════════════════════════════════════════

CREATE TABLE IF NOT EXISTS invoices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
  month TEXT NOT NULL,                         -- '2026-04'
  plan_name TEXT,
  plan_price_sar DECIMAL(10,2),
  api_cost_sar DECIMAL(10,2),
  overage_sar DECIMAL(10,2) DEFAULT 0,
  total_sar DECIMAL(10,2),
  profit_sar DECIMAL(10,2),
  status TEXT DEFAULT 'pending' CHECK (status IN ('pending','paid','overdue')),
  payment_ref TEXT,
  paid_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(tenant_id, month)
);

CREATE TABLE IF NOT EXISTS budget_config (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE UNIQUE,
  monthly_budget_sar DECIMAL(10,2),
  throttle_at_percent INTEGER DEFAULT 90,
  hard_limit_at_percent INTEGER DEFAULT 100,
  overage_allowed BOOLEAN DEFAULT false,
  overage_rate_multiplier DECIMAL(4,2) DEFAULT 1.5,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- ═══════════════════════════════════════════════════════════════════
-- CRON / SESSIONS / APPROVALS
-- ═══════════════════════════════════════════════════════════════════

CREATE TABLE IF NOT EXISTS cron_jobs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  schedule TEXT NOT NULL,
  timezone TEXT DEFAULT 'Asia/Riyadh',
  payload JSONB NOT NULL DEFAULT '{"kind": "systemEvent"}',
  delivery JSONB DEFAULT '{"mode": "announce"}',
  enabled BOOLEAN DEFAULT true,
  last_run_at TIMESTAMP WITH TIME ZONE,
  next_run_at TIMESTAMP WITH TIME ZONE NOT NULL,
  run_count INTEGER DEFAULT 0,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS cron_executions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  job_id UUID NOT NULL REFERENCES cron_jobs(id) ON DELETE CASCADE,
  tenant_id UUID NOT NULL,
  executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  success BOOLEAN NOT NULL,
  output TEXT,
  error TEXT,
  duration_ms INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS sessions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  label TEXT,
  kind TEXT NOT NULL DEFAULT 'isolated',
  status TEXT NOT NULL DEFAULT 'active',
  model TEXT,
  thinking BOOLEAN DEFAULT false,
  timeout_seconds INTEGER,
  parent_session_id UUID REFERENCES sessions(id) ON DELETE SET NULL,
  root_workspace_path TEXT NOT NULL,
  message_count INTEGER DEFAULT 0,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  last_message_at TIMESTAMP WITH TIME ZONE
);

CREATE TABLE IF NOT EXISTS session_messages (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
  role TEXT NOT NULL,
  content TEXT NOT NULL,
  tool_call_id TEXT,
  tool_name TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS approval_requests (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  session_id UUID REFERENCES sessions(id) ON DELETE SET NULL,
  tool_name TEXT NOT NULL,
  tool_args JSONB NOT NULL,
  reason TEXT NOT NULL,
  risk_level TEXT NOT NULL DEFAULT 'medium',
  status TEXT NOT NULL DEFAULT 'pending',
  requested_by TEXT NOT NULL,
  approved_by TEXT,
  approved_at TIMESTAMP WITH TIME ZONE,
  expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- ═══════════════════════════════════════════════════════════════════
-- LONG-TERM MEMORY (remember/recall tools)
-- ═══════════════════════════════════════════════════════════════════

CREATE TABLE IF NOT EXISTS customer_memories (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  customer_id TEXT NOT NULL DEFAULT '',  -- '' = tenant-wide memory
  key TEXT NOT NULL,
  value TEXT NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(tenant_id, customer_id, key)
);

-- ═══════════════════════════════════════════════════════════════════
-- ZATCA E-INVOICES (tenant → end customer; NOT platform billing above)
-- ═══════════════════════════════════════════════════════════════════

CREATE TABLE IF NOT EXISTS zatca_invoices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  customer_id TEXT NOT NULL,

  invoice_number TEXT NOT NULL,
  invoice_type TEXT NOT NULL DEFAULT 'simplified'
    CHECK (invoice_type IN ('simplified', 'standard')),

  -- Seller snapshot at issuance time
  seller_name TEXT NOT NULL,
  seller_vat_number TEXT NOT NULL,
  seller_cr_number TEXT,

  -- Buyer
  buyer_name TEXT NOT NULL,
  buyer_vat_number TEXT,

  -- Items + money
  items JSONB NOT NULL,
  subtotal NUMERIC(14,2) NOT NULL,
  vat_total NUMERIC(14,2) NOT NULL,
  total NUMERIC(14,2) NOT NULL,
  currency TEXT NOT NULL DEFAULT 'SAR',

  -- ZATCA Phase-1 artifacts
  ubl_xml TEXT NOT NULL,
  qr_base64 TEXT NOT NULL,

  -- Phase-2 (filled when signing/clearance lands)
  zatca_uuid UUID,
  zatca_hash TEXT,
  zatca_clearance_response JSONB,

  -- Status & approval
  status TEXT NOT NULL DEFAULT 'pending_approval'
    CHECK (status IN ('draft','pending_approval','issued','cleared','rejected','cancelled')),
  approval_request_id UUID REFERENCES approval_requests(id) ON DELETE SET NULL,

  -- Timestamps
  issued_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
  approved_at TIMESTAMP WITH TIME ZONE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),

  UNIQUE(tenant_id, invoice_number)
);

-- ═══════════════════════════════════════════════════════════════════
-- INDEXES
-- ═══════════════════════════════════════════════════════════════════

CREATE INDEX IF NOT EXISTS idx_customers_tenant ON customers(tenant_id);
CREATE INDEX IF NOT EXISTS idx_messages_tenant ON messages(tenant_id);
CREATE INDEX IF NOT EXISTS idx_messages_customer ON messages(customer_id);
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(tenant_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_usage_tenant ON usage(tenant_id);
CREATE INDEX IF NOT EXISTS idx_usage_date ON usage(tenant_id, date DESC);
CREATE INDEX IF NOT EXISTS idx_documents_tenant ON documents(tenant_id);
CREATE INDEX IF NOT EXISTS idx_document_chunks_tenant ON document_chunks(tenant_id);
CREATE INDEX IF NOT EXISTS idx_document_chunks_document ON document_chunks(document_id);
CREATE INDEX IF NOT EXISTS idx_document_chunks_embedding
  ON document_chunks USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

CREATE INDEX IF NOT EXISTS idx_invoices_tenant_id ON invoices(tenant_id);
CREATE INDEX IF NOT EXISTS idx_invoices_month ON invoices(month);
CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status);
CREATE INDEX IF NOT EXISTS idx_budget_config_tenant ON budget_config(tenant_id);

CREATE INDEX IF NOT EXISTS idx_cron_jobs_tenant ON cron_jobs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_cron_jobs_enabled ON cron_jobs(enabled) WHERE enabled = true;
CREATE INDEX IF NOT EXISTS idx_cron_jobs_next_run ON cron_jobs(next_run_at) WHERE enabled = true;
CREATE INDEX IF NOT EXISTS idx_cron_executions_job ON cron_executions(job_id);
CREATE INDEX IF NOT EXISTS idx_cron_executions_tenant ON cron_executions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_cron_executions_executed_at ON cron_executions(executed_at DESC);

CREATE INDEX IF NOT EXISTS idx_sessions_tenant ON sessions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status);
CREATE INDEX IF NOT EXISTS idx_sessions_kind ON sessions(kind);
CREATE INDEX IF NOT EXISTS idx_session_messages_session ON session_messages(session_id);
CREATE INDEX IF NOT EXISTS idx_session_messages_created_at ON session_messages(created_at);

CREATE INDEX IF NOT EXISTS idx_approval_tenant ON approval_requests(tenant_id);
CREATE INDEX IF NOT EXISTS idx_approval_session ON approval_requests(session_id);
CREATE INDEX IF NOT EXISTS idx_approval_status ON approval_requests(status);
CREATE INDEX IF NOT EXISTS idx_approval_expires ON approval_requests(expires_at) WHERE status = 'pending';

CREATE INDEX IF NOT EXISTS idx_customer_memories_tenant ON customer_memories(tenant_id);
CREATE INDEX IF NOT EXISTS idx_customer_memories_lookup
  ON customer_memories(tenant_id, customer_id, key);
CREATE INDEX IF NOT EXISTS idx_customer_memories_key_trgm
  ON customer_memories USING gin (key gin_trgm_ops);

CREATE INDEX IF NOT EXISTS idx_zatca_invoices_tenant ON zatca_invoices(tenant_id);
CREATE INDEX IF NOT EXISTS idx_zatca_invoices_customer
  ON zatca_invoices(tenant_id, customer_id);
CREATE INDEX IF NOT EXISTS idx_zatca_invoices_status
  ON zatca_invoices(tenant_id, status) WHERE status IN ('pending_approval','issued');
CREATE INDEX IF NOT EXISTS idx_zatca_invoices_issued_at
  ON zatca_invoices(tenant_id, issued_at DESC);

-- ═══════════════════════════════════════════════════════════════════
-- RPC FUNCTIONS
-- ═══════════════════════════════════════════════════════════════════

CREATE OR REPLACE FUNCTION match_documents(
  query_embedding VECTOR(1536),
  match_tenant_id UUID,
  match_threshold FLOAT DEFAULT 0.7,
  match_count INT DEFAULT 5
)
RETURNS TABLE (
  id UUID,
  document_id UUID,
  content TEXT,
  metadata JSONB,
  similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN QUERY
  SELECT
    dc.id,
    dc.document_id,
    dc.content,
    dc.metadata,
    1 - (dc.embedding <=> query_embedding) AS similarity
  FROM document_chunks dc
  WHERE dc.tenant_id = match_tenant_id
    AND 1 - (dc.embedding <=> query_embedding) > match_threshold
  ORDER BY dc.embedding <=> query_embedding
  LIMIT match_count;
END;
$$;

CREATE OR REPLACE FUNCTION upsert_daily_usage(
  p_tenant_id UUID,
  p_date DATE,
  p_messages INT DEFAULT 0,
  p_tokens_in BIGINT DEFAULT 0,
  p_tokens_out BIGINT DEFAULT 0,
  p_cost DECIMAL DEFAULT 0,
  p_new_customers INT DEFAULT 0,
  p_active_customers INT DEFAULT 0
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
BEGIN
  INSERT INTO usage (tenant_id, date, messages_count, tokens_input, tokens_output, cost_usd, customers_new, customers_active)
  VALUES (p_tenant_id, p_date, p_messages, p_tokens_in, p_tokens_out, p_cost, p_new_customers, p_active_customers)
  ON CONFLICT (tenant_id, date) DO UPDATE SET
    messages_count = usage.messages_count + EXCLUDED.messages_count,
    tokens_input = usage.tokens_input + EXCLUDED.tokens_input,
    tokens_output = usage.tokens_output + EXCLUDED.tokens_output,
    cost_usd = usage.cost_usd + EXCLUDED.cost_usd,
    customers_new = usage.customers_new + EXCLUDED.customers_new,
    customers_active = GREATEST(usage.customers_active, EXCLUDED.customers_active);
END;
$$;

-- ═══════════════════════════════════════════════════════════════════
-- ROW LEVEL SECURITY
-- ═══════════════════════════════════════════════════════════════════
-- Service role bypasses RLS by design, so the gateway's service-role queries
-- keep working. RLS protects any anon-key/JWT path (dashboard direct queries,
-- future tenant-scoped tools). See migrations/007-add-owner-id-and-rls.ts.

CREATE INDEX IF NOT EXISTS idx_tenants_owner ON tenants(owner_id);

-- Backfill owner_id from settings.owner_id where pre-007 onboarding stuffed it
UPDATE tenants
SET owner_id = (settings->>'owner_id')::uuid
WHERE owner_id IS NULL
  AND settings ? 'owner_id'
  AND (settings->>'owner_id') ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';

CREATE OR REPLACE FUNCTION public.auth_owns_tenant(target_tenant_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = public
AS $$
  SELECT EXISTS (
    SELECT 1 FROM public.tenants t
    WHERE t.id = target_tenant_id AND t.owner_id = auth.uid()
  );
$$;
REVOKE ALL ON FUNCTION public.auth_owns_tenant(UUID) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.auth_owns_tenant(UUID) TO authenticated, anon, service_role;

ALTER TABLE tenants            ENABLE ROW LEVEL SECURITY;
ALTER TABLE customers          ENABLE ROW LEVEL SECURITY;
ALTER TABLE messages           ENABLE ROW LEVEL SECURITY;
ALTER TABLE usage              ENABLE ROW LEVEL SECURITY;
ALTER TABLE documents          ENABLE ROW LEVEL SECURITY;
ALTER TABLE document_chunks    ENABLE ROW LEVEL SECURITY;
ALTER TABLE invoices           ENABLE ROW LEVEL SECURITY;
ALTER TABLE budget_config      ENABLE ROW LEVEL SECURITY;
ALTER TABLE cron_jobs          ENABLE ROW LEVEL SECURITY;
ALTER TABLE cron_executions    ENABLE ROW LEVEL SECURITY;
ALTER TABLE sessions           ENABLE ROW LEVEL SECURITY;
ALTER TABLE session_messages   ENABLE ROW LEVEL SECURITY;
ALTER TABLE approval_requests  ENABLE ROW LEVEL SECURITY;
ALTER TABLE customer_memories  ENABLE ROW LEVEL SECURITY;
ALTER TABLE zatca_invoices     ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS tenant_owner_only ON tenants;
CREATE POLICY tenant_owner_only ON tenants
  FOR ALL TO authenticated
  USING (owner_id = auth.uid())
  WITH CHECK (owner_id = auth.uid());

DROP POLICY IF EXISTS tenant_isolation ON customers;
CREATE POLICY tenant_isolation ON customers FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON messages;
CREATE POLICY tenant_isolation ON messages FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON usage;
CREATE POLICY tenant_isolation ON usage FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON documents;
CREATE POLICY tenant_isolation ON documents FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON document_chunks;
CREATE POLICY tenant_isolation ON document_chunks FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON invoices;
CREATE POLICY tenant_isolation ON invoices FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON budget_config;
CREATE POLICY tenant_isolation ON budget_config FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON cron_jobs;
CREATE POLICY tenant_isolation ON cron_jobs FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON cron_executions;
CREATE POLICY tenant_isolation ON cron_executions FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON sessions;
CREATE POLICY tenant_isolation ON sessions FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON approval_requests;
CREATE POLICY tenant_isolation ON approval_requests FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON customer_memories;
CREATE POLICY tenant_isolation ON customer_memories FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

DROP POLICY IF EXISTS tenant_isolation ON zatca_invoices;
CREATE POLICY tenant_isolation ON zatca_invoices FOR ALL TO authenticated
  USING (public.auth_owns_tenant(tenant_id)) WITH CHECK (public.auth_owns_tenant(tenant_id));

-- session_messages joins through sessions for its tenant
DROP POLICY IF EXISTS tenant_isolation ON session_messages;
CREATE POLICY tenant_isolation ON session_messages FOR ALL TO authenticated
  USING (
    public.auth_owns_tenant(
      (SELECT s.tenant_id FROM sessions s WHERE s.id = session_messages.session_id)
    )
  )
  WITH CHECK (
    public.auth_owns_tenant(
      (SELECT s.tenant_id FROM sessions s WHERE s.id = session_messages.session_id)
    )
  );

-- ═══════════════════════════════════════════════════════════════════
-- DONE
-- ═══════════════════════════════════════════════════════════════════
-- Verify with:
--   SELECT table_name FROM information_schema.tables
--   WHERE table_schema='public' ORDER BY table_name;
-- Expected (15 tables):
--   approval_requests, budget_config, cron_executions, cron_jobs,
--   customer_memories, customers, document_chunks, documents, invoices,
--   messages, session_messages, sessions, tenants, usage, zatca_invoices
