/**
 * src/tenants/manager.ts
 * مدير المستأجرين — إدارة الحسابات والعملاء ومساحات العمل
 */
import { z } from 'zod';
import { v4 as uuidv4 } from 'uuid';
import { createChildLogger } from '../utils/logger.js';
import { supabase } from '../utils/supabase.js';
import { provisionWorkspace } from './workspace.js';
const log = createChildLogger('tenants:manager');
// ─── Schemas ─────────────────────────────────────────────────────────
export const createTenantSchema = z.object({
    business_name: z.string().min(1).max(200),
    business_name_ar: z.string().optional(),
    agent_name: z.string().min(1).max(100).default('مساعد'),
    whatsapp_phone: z.string().regex(/^\+\d{10,15}$/, 'Invalid phone format — use +966...'),
    owner_id: z.string().uuid('owner_id must be the authenticated auth.users.id'),
    owner_name: z.string().min(1).max(200),
    owner_phone: z.string().regex(/^\+\d{10,15}$/).optional(),
    owner_email: z.string().email().optional(),
    plan: z.enum(['trial', 'starter', 'pro', 'enterprise']).default('trial'),
    settings: z.record(z.string(), z.unknown()).optional(),
});
// ─── Tenant Operations ───────────────────────────────────────────────
/**
 * البحث عن مستأجر برقم الواتساب
 * هذه الدالة الأكثر استخداماً — كل رسالة واردة تمر من هنا
 */
export async function getTenantByPhone(whatsappPhone) {
    // Was filtering by status='active', but new tenants are created with
    // status='trial'. That made the duplicate-phone guard never fire and
    // let the same owner re-create a tenant on every retry (e.g. when the
    // onboarding wizard's fetch dropped after the server already succeeded).
    // Include both states — the guard exists to stop duplicates, not to
    // distinguish billing tiers.
    const { data, error } = await supabase
        .from('tenants')
        .select('*')
        .eq('whatsapp_phone', whatsappPhone)
        .in('status', ['active', 'trial'])
        .single();
    if (error) {
        if (error.code === 'PGRST116')
            return null; // not found
        log.error({ phone: whatsappPhone, error: error.message }, 'Failed to find tenant by phone');
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
export async function getTenantByOwnerId(ownerId) {
    // Returns the tenant a given owner already provisioned, if any. Used by
    // the onboarding route to short-circuit retries: if the user already has
    // a tenant (because a previous /start succeeded server-side even though
    // the fetch failed client-side), return it instead of throwing on the
    // duplicate-phone guard or duplicating workspace setup.
    const { data, error } = await supabase
        .from('tenants')
        .select('*')
        .eq('owner_id', ownerId)
        .in('status', ['active', 'trial'])
        .single();
    if (error) {
        if (error.code === 'PGRST116')
            return null;
        log.error({ ownerId, error: error.message }, 'Failed to find tenant by owner');
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
/**
 * البحث عن مستأجر بالمعرف
 */
export async function getTenantById(id) {
    const { data, error } = await supabase
        .from('tenants')
        .select('*')
        .eq('id', id)
        .single();
    if (error) {
        if (error.code === 'PGRST116')
            return null;
        log.error({ tenantId: id, error: error.message }, 'Failed to find tenant');
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
/**
 * إنشاء مستأجر جديد + تجهيز مساحة العمل
 */
export async function createTenant(input) {
    const validated = createTenantSchema.parse(input);
    const id = uuidv4();
    log.info({ id, businessName: validated.business_name, phone: validated.whatsapp_phone }, 'Creating new tenant');
    // التحقق من عدم وجود رقم مكرر
    const existing = await getTenantByPhone(validated.whatsapp_phone);
    if (existing) {
        throw new Error(`Phone number ${validated.whatsapp_phone} is already registered`);
    }
    // إنشاء في قاعدة البيانات
    const now = new Date().toISOString();
    const tenant = {
        id,
        owner_id: validated.owner_id,
        business_name: validated.business_name,
        business_name_ar: validated.business_name_ar,
        agent_name: validated.agent_name,
        whatsapp_phone: validated.whatsapp_phone,
        owner_name: validated.owner_name,
        owner_phone: validated.owner_phone,
        owner_email: validated.owner_email,
        plan: validated.plan,
        status: validated.plan === 'trial' ? 'trial' : 'active',
        settings: validated.settings ?? {},
        created_at: now,
        updated_at: now,
    };
    const { error } = await supabase.from('tenants').insert(tenant);
    if (error) {
        log.error({ id, error: error.message }, 'Failed to create tenant in database');
        throw new Error(`Failed to create tenant: ${error.message}`);
    }
    // تجهيز مساحة العمل
    await provisionWorkspace(id, validated.business_name, validated.agent_name);
    log.info({ id, businessName: validated.business_name }, 'Tenant created successfully ✅');
    return tenant;
}
/**
 * تحديث بيانات المستأجر
 */
export async function updateTenant(id, updates) {
    const { data, error } = await supabase
        .from('tenants')
        .update({ ...updates, updated_at: new Date().toISOString() })
        .eq('id', id)
        .select()
        .single();
    if (error) {
        log.error({ tenantId: id, error: error.message }, 'Failed to update tenant');
        throw new Error(`Failed to update tenant: ${error.message}`);
    }
    return data;
}
// ─── Customer Operations ─────────────────────────────────────────────
/**
 * البحث عن عميل أو إنشاء سجل جديد
 * يُستدعى مع كل رسالة واردة
 */
export async function getOrCreateCustomer(tenantId, phone, name) {
    // بحث أولاً
    const { data: existing } = await supabase
        .from('customers')
        .select('*')
        .eq('tenant_id', tenantId)
        .eq('phone', phone)
        .single();
    if (existing) {
        // تحديث آخر ظهور وعدد الرسائل
        const { data: updated } = await supabase
            .from('customers')
            .update({
            last_seen_at: new Date().toISOString(),
            message_count: (existing.message_count ?? 0) + 1,
            ...(name && !existing.name ? { name } : {}),
        })
            .eq('id', existing.id)
            .select()
            .single();
        return (updated ?? existing);
    }
    // إنشاء عميل جديد
    const id = uuidv4();
    const now = new Date().toISOString();
    const customer = {
        id,
        tenant_id: tenantId,
        phone,
        name,
        metadata: {},
        first_seen_at: now,
        last_seen_at: now,
        message_count: 1,
    };
    const { error } = await supabase.from('customers').insert(customer);
    if (error) {
        log.error({ tenantId, phone, error: error.message }, 'Failed to create customer');
        throw new Error(`Failed to create customer: ${error.message}`);
    }
    log.info({ tenantId, customerId: id, phone }, 'New customer created');
    return customer;
}
/**
 * سرد عملاء المستأجر
 */
export async function listCustomers(tenantId, options = {}) {
    const { limit = 50, offset = 0 } = options;
    const { data, error, count } = await supabase
        .from('customers')
        .select('*', { count: 'exact' })
        .eq('tenant_id', tenantId)
        .order('last_seen_at', { ascending: false })
        .range(offset, offset + limit - 1);
    if (error) {
        throw new Error(`Failed to list customers: ${error.message}`);
    }
    return {
        customers: (data ?? []),
        total: count ?? 0,
    };
}
//# sourceMappingURL=manager.js.map