import { authMiddleware } from '../auth/middleware.js';
import { registerJob, unregisterJob, runJobNow, getJobRuns, startCronScheduler, shutdownCronScheduler, } from './scheduler.js';
import { supabase } from '../utils/supabase.js';
// Resolve the caller's tenant from their auth user. Cron routes only have
// authMiddleware (not tenantMiddleware) because they don't take :tenantId
// in the URL — the owner has one tenant in device mode, so we look it up
// from request.user.id. Previously every cron endpoint returned 401 with
// "Unauthorized" because request.tenant was never populated.
async function resolveOwnerTenant(request) {
    const userId = request.user?.id;
    if (!userId)
        return null;
    const { data } = await supabase
        .from('tenants')
        .select('id')
        .eq('owner_id', userId)
        .limit(1)
        .maybeSingle();
    return data?.id ?? null;
}
import { v4 as uuidv4 } from 'uuid';
export async function registerCronRoutes(app) {
    // Start scheduler on startup
    app.addHook('onReady', async () => {
        await startCronScheduler();
    });
    // Shutdown on close
    app.addHook('onClose', async () => {
        shutdownCronScheduler();
    });
    // POST /api/cron/jobs — Create a new cron job
    app.post('/api/cron/jobs', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { name, schedule, timezone, payload, delivery, enabled } = request.body;
        const tenantId = request.tenant?.id ?? await resolveOwnerTenant(request);
        if (!tenantId) {
            return reply.status(401).send({ error: 'Unauthorized' });
        }
        const jobId = uuidv4();
        const now = new Date().toISOString();
        const { data, error } = await supabase
            .from('cron_jobs')
            .insert({
            id: jobId,
            tenant_id: tenantId,
            name,
            schedule,
            timezone: timezone || 'Asia/Riyadh',
            payload: payload || { kind: 'systemEvent' },
            delivery: delivery || { mode: 'announce' },
            enabled: enabled !== false,
            next_run_at: calculateNextRun(schedule, timezone),
            created_at: now,
            updated_at: now,
        })
            .select()
            .single();
        if (error) {
            return reply.status(500).send({ error: error.message });
        }
        // Register in scheduler
        await registerJob(data);
        reply.send({ success: true, job: data });
    });
    // GET /api/cron/jobs — List all jobs for tenant
    app.get('/api/cron/jobs', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const tenantId = request.tenant?.id ?? await resolveOwnerTenant(request);
        if (!tenantId) {
            return reply.status(401).send({ error: 'Unauthorized' });
        }
        const { data, error } = await supabase
            .from('cron_jobs')
            .select('*')
            .eq('tenant_id', tenantId)
            .order('created_at', { ascending: false });
        if (error) {
            return reply.status(500).send({ error: error.message });
        }
        reply.send({ jobs: data });
    });
    // GET /api/cron/jobs/:id — Get job details
    app.get('/api/cron/jobs/:id', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { id } = request.params;
        const tenantId = request.tenant?.id;
        const { data, error } = await supabase
            .from('cron_jobs')
            .select('*')
            .eq('id', id)
            .eq('tenant_id', tenantId)
            .single();
        if (error) {
            return reply.status(404).send({ error: 'Job not found' });
        }
        reply.send({ job: data });
    });
    // PUT /api/cron/jobs/:id — Update job
    app.put('/api/cron/jobs/:id', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { id } = request.params;
        const { name, schedule, timezone, payload, delivery, enabled } = request.body;
        const tenantId = request.tenant?.id;
        const updateData = { updated_at: new Date().toISOString() };
        if (name)
            updateData.name = name;
        if (schedule)
            updateData.schedule = schedule;
        if (timezone)
            updateData.timezone = timezone;
        if (payload)
            updateData.payload = payload;
        if (delivery)
            updateData.delivery = delivery;
        if (enabled !== undefined)
            updateData.enabled = enabled;
        const { data, error } = await supabase
            .from('cron_jobs')
            .update(updateData)
            .eq('id', id)
            .eq('tenant_id', tenantId)
            .select()
            .single();
        if (error) {
            return reply.status(500).send({ error: error.message });
        }
        // Update scheduler
        if (enabled !== false) {
            await registerJob(data);
        }
        else {
            await unregisterJob(id);
        }
        reply.send({ success: true, job: data });
    });
    // DELETE /api/cron/jobs/:id — Delete job
    app.delete('/api/cron/jobs/:id', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { id } = request.params;
        const tenantId = request.tenant?.id;
        await supabase
            .from('cron_jobs')
            .delete()
            .eq('id', id)
            .eq('tenant_id', tenantId);
        await unregisterJob(id);
        reply.send({ success: true });
    });
    // POST /api/cron/jobs/:id/run — Run job immediately
    app.post('/api/cron/jobs/:id/run', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { id } = request.params;
        const tenantId = request.tenant?.id;
        // Verify tenant owns this job
        const { data: job } = await supabase
            .from('cron_jobs')
            .select('tenant_id')
            .eq('id', id)
            .single();
        if (!job || job.tenant_id !== tenantId) {
            return reply.status(404).send({ error: 'Job not found' });
        }
        const result = await runJobNow(id);
        reply.send(result);
    });
    // GET /api/cron/jobs/:id/runs — Get job execution history
    app.get('/api/cron/jobs/:id/runs', {
        preHandler: [authMiddleware],
    }, async (request, reply) => {
        const { id } = request.params;
        const { limit = 10 } = request.query;
        const runs = await getJobRuns(id, parseInt(limit));
        reply.send({ runs });
    });
}
function calculateNextRun(schedule, timezone) {
    // Simple implementation - in production, use a proper cron library
    const now = new Date();
    now.setMinutes(now.getMinutes() + 1);
    return now.toISOString();
}
//# sourceMappingURL=routes.js.map