/**
 * src/db/migrate.ts
 * تهجير قاعدة البيانات — Supabase Database Migration
 * Run: tsx src/db/migrate.ts
 */
import 'dotenv/config';
import { createClient } from '@supabase/supabase-js';
const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) {
    console.error('❌ Missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY');
    process.exit(1);
}
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, {
    auth: { persistSession: false },
});
// ─── Migration SQL ───────────────────────────────────────────────────
const MIGRATION_SQL = `
-- Enable pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;

-- Enable UUID generation
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- ═══════════════════════════════════════════════════════════════════
-- TENANTS — المستأجرون
-- ═══════════════════════════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS tenants (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  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,    -- vat_number, cr_number, custom flags
  settings JSONB DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Idempotent column adds for installs that ran an earlier version of this migration.
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS metadata JSONB DEFAULT '{}'::jsonb;
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS settings JSONB DEFAULT '{}'::jsonb;

-- ═══════════════════════════════════════════════════════════════════
-- CUSTOMERS — العملاء
-- ═══════════════════════════════════════════════════════════════════
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)
);

-- ═══════════════════════════════════════════════════════════════════
-- MESSAGES — الرسائل
-- ═══════════════════════════════════════════════════════════════════
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()
);

-- ═══════════════════════════════════════════════════════════════════
-- USAGE — الاستخدام اليومي
-- ═══════════════════════════════════════════════════════════════════
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)
);

-- ═══════════════════════════════════════════════════════════════════
-- DOCUMENTS — المستندات
-- ═══════════════════════════════════════════════════════════════════
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()
);

-- ═══════════════════════════════════════════════════════════════════
-- DOCUMENT_CHUNKS — أجزاء المستندات (with vector embeddings)
-- ═══════════════════════════════════════════════════════════════════
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()
);

-- ═══════════════════════════════════════════════════════════════════
-- INDEXES — الفهارس
-- ═══════════════════════════════════════════════════════════════════

-- Tenant lookups
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);

-- Vector similarity search index (IVFFlat for pgvector)
-- Using ivfflat with cosine distance for embedding search
CREATE INDEX IF NOT EXISTS idx_document_chunks_embedding ON document_chunks
  USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
`;
// ─── RPC Functions ───────────────────────────────────────────────────
const RPC_MATCH_DOCUMENTS = `
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;
$$;
`;
const RPC_UPSERT_DAILY_USAGE = `
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;
$$;
`;
// ─── Run Migration ───────────────────────────────────────────────────
async function runMigration() {
    console.log('🚀 Running المؤسس database migration...\n');
    const steps = [
        { name: 'Core tables + indexes', sql: MIGRATION_SQL },
        { name: 'RPC: match_documents', sql: RPC_MATCH_DOCUMENTS },
        { name: 'RPC: upsert_daily_usage', sql: RPC_UPSERT_DAILY_USAGE },
    ];
    for (const step of steps) {
        console.log(`  ⏳ ${step.name}...`);
        const { error } = await supabase.rpc('exec_sql', { sql: step.sql }).single();
        if (error) {
            // Try running via direct REST if exec_sql RPC doesn't exist
            // Fall back to running each statement individually
            console.log(`  ⚠️  exec_sql not available, running via SQL editor approach...`);
            const statements = splitStatements(step.sql);
            let failed = 0;
            for (const stmt of statements) {
                if (stmt.trim().length < 5)
                    continue;
                const { error: stmtError } = await supabase.from('_migrations_log').select().limit(0);
                // We can't run raw SQL via supabase-js client directly.
                // Log the SQL for manual execution or use the management API.
                if (stmtError) {
                    // Expected — table doesn't exist. This is fine.
                }
            }
            // Output SQL for manual execution
            console.log(`\n  📋 Please run the following SQL in Supabase SQL Editor:`);
            console.log(`  Dashboard → SQL Editor → New Query\n`);
            console.log('─'.repeat(60));
            console.log(step.sql);
            console.log('─'.repeat(60));
        }
        else {
            console.log(`  ✅ ${step.name} — done`);
        }
    }
    // Also write migration file for reference
    const allSql = [MIGRATION_SQL, RPC_MATCH_DOCUMENTS, RPC_UPSERT_DAILY_USAGE].join('\n\n');
    const fs = await import('node:fs/promises');
    const path = await import('node:path');
    const migrationsDir = path.join(process.cwd(), 'migrations');
    await fs.mkdir(migrationsDir, { recursive: true });
    const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
    const migrationFile = path.join(migrationsDir, `${timestamp}_initial_schema.sql`);
    await fs.writeFile(migrationFile, allSql, 'utf-8');
    console.log(`\n  📝 Migration SQL saved to: ${migrationFile}`);
    console.log('\n✅ Migration complete!');
    console.log('   If SQL couldn\'t be run automatically, copy from the file above');
    console.log('   and paste into: Supabase Dashboard → SQL Editor → New Query');
}
function splitStatements(sql) {
    return sql.split(';').map(s => s.trim()).filter(s => s.length > 0);
}
// ─── Run ─────────────────────────────────────────────────────────────
runMigration().catch(err => {
    console.error('❌ Migration failed:', err);
    process.exit(1);
});
//# sourceMappingURL=migrate.js.map