require('dotenv').config();
const express = require('express');
const path = require('path');
const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const twilio = require('twilio');

const whatsappService = require('./whatsappService');
const botLogic = require('./botLogic');
const { getTenantConfig, updateTenantConfig } = require('./configManager');
const { getTemporalClient } = require('./temporalClient');
const { query, initSchema } = require('./db');
const { signToken, requireAuth } = require('./authMiddleware');
const Razorpay = require('razorpay');
const { upload, initStorage, uploadFile } = require('./storage');
const AgentManager = require('./agents/AgentManager');
const prescriptionManager = require('./prescriptionManager');

const razorpayInstance = new Razorpay({
    key_id: process.env.RAZORPAY_KEY_ID || 'rzp_test_dummy_key_id',
    key_secret: process.env.RAZORPAY_KEY_SECRET || 'dummy_secret_key',
});

const app = express();
const port = 3000;

app.use(express.json());

const staticRoot = path.join(__dirname, '../');

// ── Helpers ───────────────────────────────────────────────────────────────────

function setUtf8ContentType(res, filePath) {
    if (filePath.endsWith('.html'))  res.setHeader('Content-Type', 'text/html; charset=utf-8');
    else if (filePath.endsWith('.css'))  res.setHeader('Content-Type', 'text/css; charset=utf-8');
    else if (filePath.endsWith('.js'))   res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
    else if (filePath.endsWith('.json')) res.setHeader('Content-Type', 'application/json; charset=utf-8');
}

function setNoCacheHeaders(res) {
    res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
}

function sendHtmlPage(res, filename) {
    setNoCacheHeaders(res);
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.sendFile(path.join(staticRoot, filename));
}

// Slug-safe clinic ID generator from clinic name
function slugify(name) {
    return name.toLowerCase()
        .replace(/[^\w\s-]/g, '')
        .replace(/\s+/g, '-')
        .replace(/-+/g, '-')
        .slice(0, 40);
}

async function uniqueSlug(base) {
    let slug = slugify(base);
    let attempt = slug;
    let counter = 2;
    while (true) {
        const existing = await query('SELECT id FROM tenants WHERE id = $1', [attempt]);
        if (existing.rows.length === 0) return attempt;
        attempt = `${slug}-${counter++}`;
    }
}

// ── Static files ──────────────────────────────────────────────────────────────

app.use(express.static(staticRoot, {
    setHeaders: (res, filePath) => {
        setUtf8ContentType(res, filePath);
        if (filePath.endsWith('.html')) setNoCacheHeaders(res);
    }
}));

// ── Page routes ───────────────────────────────────────────────────────────────

app.get('/',            (req, res) => sendHtmlPage(res, 'login.html'));
app.get('/admin',       (req, res) => sendHtmlPage(res, 'admin.html'));
app.get('/dashboard',   (req, res) => sendHtmlPage(res, 'dashboard.html'));
app.get('/register',    (req, res) => sendHtmlPage(res, 'register.html'));
app.get('/super-admin', (req, res) => sendHtmlPage(res, 'super-admin.html'));

// ── Multi-tenant Config API (DB-first, fallback to in-memory) ─────────────────

app.get('/api/config/:tenantId', async (req, res) => {
    try {
        const row = await query('SELECT * FROM tenants WHERE id = $1 AND status = $2', [req.params.tenantId, 'active']);
        if (row.rows.length > 0) {
            const t = row.rows[0];
            return res.json({
                name: t.name,
                logo: t.logo,
                primaryColor: t.primary_color,
                secondaryColor: t.secondary_color,
                consultationFee: t.consultation_fee,
                currency: t.currency || '₹',
                plan: t.plan,
                specialty: t.specialty,
                city: t.city,
                workingHours: t.working_hours,
                daysOff: t.days_off,
                holidays: t.holidays,
            });
        }
    } catch (err) {
        console.error('[Config API] DB error, falling back to in-memory:', err.message);
    }
    // Fallback to in-memory config
    res.json(getTenantConfig(req.params.tenantId));
});

// ── AUTH ROUTES ───────────────────────────────────────────────────────────────

app.use(express.urlencoded({ extended: true }));

/**
 * POST /api/auth/register
 * Public — submit a clinic registration for super admin approval
 */
app.post('/api/auth/register', async (req, res) => {
    const { ownerName, clinicName, specialty, city, whatsappNumber, email, password, plan } = req.body;

    if (!ownerName || !clinicName || !whatsappNumber || !email || !password) {
        return res.status(400).json({ error: 'Missing required fields' });
    }
    if (password.length < 8) {
        return res.status(400).json({ error: 'Password must be at least 8 characters' });
    }

    try {
        // Check for duplicate email in users or pending
        const dupUser    = await query('SELECT id FROM users WHERE email = $1', [email]);
        const dupPending = await query('SELECT id FROM pending_registrations WHERE email = $1 AND status = $2', [email, 'pending']);
        if (dupUser.rows.length > 0 || dupPending.rows.length > 0) {
            return res.status(409).json({ error: 'An account with this email already exists or is pending approval' });
        }

        const hash = await bcrypt.hash(password, 10);
        const result = await query(
            `INSERT INTO pending_registrations
             (owner_name, clinic_name, specialty, city, whatsapp_number, email, password_hash, plan)
             VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING id`,
            [ownerName, clinicName, specialty || null, city || null, whatsappNumber, email, hash, plan || 'basic']
        );
        res.json({ success: true, registrationId: result.rows[0].id });
    } catch (err) {
        console.error('[Register]', err);
        res.status(500).json({ error: 'Registration failed' });
    }
});

/**
 * POST /api/auth/login
 * Public — authenticate user, return JWT
 */
app.post('/api/auth/login', async (req, res) => {
    const { email, password } = req.body;
    if (!email || !password) return res.status(400).json({ error: 'Email and password required' });

    try {
        const result = await query('SELECT * FROM users WHERE email = $1', [email]);
        if (result.rows.length === 0) {
            return res.status(401).json({ error: 'Invalid credentials' });
        }
        const user = result.rows[0];

        // Check tenant status (super admin has null tenant_id — always allowed)
        if (user.tenant_id) {
            const tenant = await query('SELECT status FROM tenants WHERE id = $1', [user.tenant_id]);
            if (tenant.rows.length === 0 || tenant.rows[0].status !== 'active') {
                return res.status(403).json({ error: 'Your clinic account is suspended. Contact Curio support.' });
            }
        }

        if (user.status !== 'active') {
            return res.status(403).json({ error: 'Your account is inactive. Contact your clinic admin.' });
        }

        const match = await bcrypt.compare(password, user.password_hash);
        if (!match) return res.status(401).json({ error: 'Invalid credentials' });

        const token = signToken({
            userId: user.id,
            email: user.email,
            name: user.name,
            role: user.role,
            tenantId: user.tenant_id,
        });

        res.json({ success: true, token, role: user.role, tenantId: user.tenant_id, name: user.name });
    } catch (err) {
        console.error('[Login]', err);
        res.status(500).json({ error: 'Login failed' });
    }
});

/**
 * GET /api/auth/me
 * Returns current user info (for page load verification)
 */
app.get('/api/auth/me', requireAuth(), (req, res) => {
    res.json({ user: req.user });
});

// ── SUPER ADMIN ROUTES ────────────────────────────────────────────────────────

/**
 * GET /api/super/stats
 */
app.get('/api/super/stats', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        const [clinics, pending, users] = await Promise.all([
            query("SELECT COUNT(*) FROM tenants WHERE status = 'active'"),
            query("SELECT COUNT(*) FROM pending_registrations WHERE status = 'pending'"),
            query("SELECT COUNT(*) FROM users WHERE role != 'SUPER_ADMIN'"),
        ]);
        res.json({
            activeClinics:  parseInt(clinics.rows[0].count),
            pendingCount:   parseInt(pending.rows[0].count),
            totalUsers:     parseInt(users.rows[0].count),
        });
    } catch (err) {
        console.error('[Super Stats]', err);
        res.status(500).json({ error: 'Failed to fetch stats' });
    }
});

/**
 * GET /api/super/clinics
 */
app.get('/api/super/clinics', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        const result = await query(
            `SELECT t.*, COUNT(u.id) AS user_count
             FROM tenants t
             LEFT JOIN users u ON u.tenant_id = t.id
             GROUP BY t.id ORDER BY t.created_at DESC`
        );
        res.json(result.rows);
    } catch (err) {
        console.error('[Super Clinics]', err);
        res.status(500).json({ error: 'Failed to fetch clinics' });
    }
});

/**
 * POST /api/super/clinics
 * Direct clinic creation by super admin (bypasses pending flow)
 */
app.post('/api/super/clinics', requireAuth('SUPER_ADMIN'), async (req, res) => {
    const { ownerName, ownerEmail, ownerPassword, clinicName, specialty, city, whatsappNumber, plan,
            primaryColor, secondaryColor, consultationFee } = req.body;

    if (!ownerName || !ownerEmail || !ownerPassword || !clinicName) {
        return res.status(400).json({ error: 'Missing required fields' });
    }

    try {
        const tenantId = await uniqueSlug(clinicName);
        const hash = await bcrypt.hash(ownerPassword, 10);

        await query('BEGIN');
        try {
            await query(
                `INSERT INTO tenants (id, name, logo, primary_color, secondary_color, consultation_fee, plan, specialty, city, whatsapp_number)
                 VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)`,
                [tenantId, clinicName, clinicName[0].toUpperCase(),
                 primaryColor || '#0F172A', secondaryColor || '#38BDF8',
                 consultationFee || 500, plan || 'basic',
                 specialty || null, city || null, whatsappNumber || null]
            );
            const userResult = await query(
                `INSERT INTO users (tenant_id, email, password_hash, name, role)
                 VALUES ($1,$2,$3,$4,'OWNER') RETURNING id`,
                [tenantId, ownerEmail, hash, ownerName]
            );
            await query('COMMIT');
            res.json({ success: true, tenantId, userId: userResult.rows[0].id });
        } catch (inner) {
            await query('ROLLBACK');
            throw inner;
        }
    } catch (err) {
        console.error('[Super Create Clinic]', err);
        if (err.code === '23505') return res.status(409).json({ error: 'Email already in use' });
        res.status(500).json({ error: 'Failed to create clinic' });
    }
});

/**
 * PATCH /api/super/clinics/:id/status
 * Toggle active / suspended
 */
app.patch('/api/super/clinics/:id/status', requireAuth('SUPER_ADMIN'), async (req, res) => {
    const { status } = req.body;
    if (!['active', 'suspended'].includes(status)) {
        return res.status(400).json({ error: 'Status must be active or suspended' });
    }
    try {
        await query('UPDATE tenants SET status = $1 WHERE id = $2', [status, req.params.id]);
        res.json({ success: true });
    } catch (err) {
        console.error('[Super Clinic Status]', err);
        res.status(500).json({ error: 'Failed to update status' });
    }
});

/**
 * DELETE /api/super/clinics/:id
 */
app.delete('/api/super/clinics/:id', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        await query('DELETE FROM tenants WHERE id = $1', [req.params.id]);
        res.json({ success: true });
    } catch (err) {
        console.error('[Super Delete Clinic]', err);
        res.status(500).json({ error: 'Failed to delete clinic' });
    }
});

/**
 * GET /api/super/clinics/:id/users
 */
app.get('/api/super/clinics/:id/users', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        const result = await query(
            `SELECT id, name, email, role, status, created_at FROM users WHERE tenant_id = $1 ORDER BY created_at`,
            [req.params.id]
        );
        res.json(result.rows);
    } catch (err) {
        console.error('[Super Clinic Users]', err);
        res.status(500).json({ error: 'Failed to fetch users' });
    }
});

/**
 * POST /api/super/clinics/:id/users
 * Add a user to a clinic
 */
app.post('/api/super/clinics/:id/users', requireAuth('SUPER_ADMIN'), async (req, res) => {
    const { name, email, password, role } = req.body;
    const validRoles = ['OWNER', 'DOCTOR', 'RECEPTIONIST', 'PHARMACIST', 'LAB_TECH'];
    if (!name || !email || !password || !role) return res.status(400).json({ error: 'Missing required fields' });
    if (!validRoles.includes(role)) return res.status(400).json({ error: 'Invalid role' });

    try {
        const hash = await bcrypt.hash(password, 10);
        const result = await query(
            `INSERT INTO users (tenant_id, email, password_hash, name, role) VALUES ($1,$2,$3,$4,$5) RETURNING id`,
            [req.params.id, email, hash, name, role]
        );
        res.json({ success: true, userId: result.rows[0].id });
    } catch (err) {
        if (err.code === '23505') return res.status(409).json({ error: 'Email already in use' });
        console.error('[Super Add User]', err);
        res.status(500).json({ error: 'Failed to create user' });
    }
});

/**
 * PATCH /api/super/users/:userId/status
 */
app.patch('/api/super/users/:userId/status', requireAuth('SUPER_ADMIN'), async (req, res) => {
    const { status } = req.body;
    if (!['active', 'inactive'].includes(status)) return res.status(400).json({ error: 'Invalid status' });
    try {
        await query('UPDATE users SET status = $1 WHERE id = $2 AND role != $3', [status, req.params.userId, 'SUPER_ADMIN']);
        res.json({ success: true });
    } catch (err) {
        console.error('[Super User Status]', err);
        res.status(500).json({ error: 'Failed to update user status' });
    }
});

/**
 * DELETE /api/super/users/:userId
 */
app.delete('/api/super/users/:userId', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        await query('DELETE FROM users WHERE id = $1 AND role != $2', [req.params.userId, 'SUPER_ADMIN']);
        res.json({ success: true });
    } catch (err) {
        console.error('[Super Delete User]', err);
        res.status(500).json({ error: 'Failed to delete user' });
    }
});

/**
 * GET /api/super/pending
 */
app.get('/api/super/pending', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        const result = await query(
            `SELECT id, owner_name, clinic_name, specialty, city, whatsapp_number, email, plan, status, created_at
             FROM pending_registrations ORDER BY created_at DESC`
        );
        res.json(result.rows);
    } catch (err) {
        console.error('[Super Pending]', err);
        res.status(500).json({ error: 'Failed to fetch pending registrations' });
    }
});

/**
 * POST /api/super/pending/:id/approve
 * Creates tenant + owner user, marks pending as approved
 */
app.post('/api/super/pending/:id/approve', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        const result = await query('SELECT * FROM pending_registrations WHERE id = $1', [req.params.id]);
        if (result.rows.length === 0) return res.status(404).json({ error: 'Registration not found' });

        const p = result.rows[0];
        if (p.status !== 'pending') return res.status(400).json({ error: 'Already processed' });

        const tenantId = await uniqueSlug(p.clinic_name);

        await query('BEGIN');
        try {
            await query(
                `INSERT INTO tenants (id, name, logo, specialty, city, whatsapp_number, plan)
                 VALUES ($1,$2,$3,$4,$5,$6,$7)`,
                [tenantId, p.clinic_name, p.clinic_name[0].toUpperCase(),
                 p.specialty, p.city, p.whatsapp_number, p.plan]
            );
            await query(
                `INSERT INTO users (tenant_id, email, password_hash, name, role)
                 VALUES ($1,$2,$3,$4,'OWNER')`,
                [tenantId, p.email, p.password_hash, p.owner_name]
            );
            await query(
                `UPDATE pending_registrations SET status = 'approved' WHERE id = $1`,
                [p.id]
            );
            await query('COMMIT');
            res.json({ success: true, tenantId });
        } catch (inner) {
            await query('ROLLBACK');
            throw inner;
        }
    } catch (err) {
        console.error('[Super Approve]', err);
        if (err.code === '23505') return res.status(409).json({ error: 'Email already registered' });
        res.status(500).json({ error: 'Failed to approve registration' });
    }
});

/**
 * POST /api/super/pending/:id/reject
 */
app.post('/api/super/pending/:id/reject', requireAuth('SUPER_ADMIN'), async (req, res) => {
    try {
        await query("UPDATE pending_registrations SET status = 'rejected' WHERE id = $1", [req.params.id]);
        res.json({ success: true });
    } catch (err) {
        console.error('[Super Reject]', err);
        res.status(500).json({ error: 'Failed to reject registration' });
    }
});

// ── AI AGENTS CONFIGURATION ───────────────────────────────────────────────────

app.get('/api/clinic/agents', requireAuth('OWNER'), async (req, res) => {
    try {
        const result = await query(
            'SELECT agent_type, is_active, config FROM agent_configs WHERE tenant_id = $1',
            [req.user.tenantId]
        );
        res.json(result.rows);
    } catch (err) {
        console.error('[Agents API]', err);
        res.status(500).json({ error: 'Failed to fetch agent configs' });
    }
});

app.patch('/api/clinic/agents/:type', requireAuth('OWNER'), async (req, res) => {
    const { type } = req.params;
    const { isActive, config } = req.body;
    
    try {
        await query(
            `INSERT INTO agent_configs (tenant_id, agent_type, is_active, config)
             VALUES ($1, $2, $3, $4::jsonb)
             ON CONFLICT (tenant_id, agent_type) 
             DO UPDATE SET is_active = EXCLUDED.is_active, config = EXCLUDED.config`,
            [req.user.tenantId, type.toUpperCase(), isActive, JSON.stringify(config || {})]
        );
        res.json({ success: true });
    } catch (err) {
        console.error('[Agents API Update]', err);
        res.status(500).json({ error: 'Failed to update agent config' });
    }
});

// ── CLINIC OPERATIONS (QUEUE & PATIENTS) ──────────────────────────────────────

/**
 * GET /api/clinic/queue
 * Fetch the live queue for the tenant
 */
app.get('/api/clinic/queue', requireAuth(), async (req, res) => {
    try {
        const tenantId = req.user.tenantId;
        const result = await query(
            `SELECT v.*, p.name as patient_name, p.whatsapp_number, p.age, p.gender, p.display_id
             FROM visits v
             JOIN patients p ON v.patient_id = p.id
             WHERE v.tenant_id = $1 AND v.status IN ('waiting', 'in-room')
             ORDER BY v.created_at ASC`,
            [tenantId]
        );
        res.json(result.rows);
    } catch (err) {
        console.error('[Clinic Queue]', err);
        res.status(500).json({ error: 'Failed to fetch queue' });
    }
});

/**
 * POST /api/clinic/walk-in
 * Register a new walk-in patient and add to queue
 */
app.post('/api/clinic/walk-in', requireAuth(), async (req, res) => {
    const { name, whatsappNumber, age, gender, fee } = req.body;
    const tenantId = req.user.tenantId;

    if (!name || !whatsappNumber) return res.status(400).json({ error: 'Name and WhatsApp number are required' });

    try {
        await query('BEGIN');
        
        // Find or create patient
        let patientResult = await query(
            'SELECT id FROM patients WHERE tenant_id = $1 AND whatsapp_number = $2',
            [tenantId, whatsappNumber]
        );
        
        let patientId;
        if (patientResult.rows.length > 0) {
            patientId = patientResult.rows[0].id;
        } else {
            // Generate display ID
            const countRes = await query('SELECT count(*) FROM patients WHERE tenant_id = $1', [tenantId]);
            const nextNum = parseInt(countRes.rows[0].count) + 1001;
            const displayId = `CF-${nextNum}`;

            const insertPatient = await query(
                `INSERT INTO patients (tenant_id, display_id, name, whatsapp_number, age, gender)
                 VALUES ($1, $2, $3, $4, $5, $6) RETURNING id`,
                [tenantId, displayId, name, whatsappNumber, age || null, gender || null]
            );
            patientId = insertPatient.rows[0].id;
        }

        // Generate Token Number (simple count-based for the day)
        const todayStr = new Date().toISOString().split('T')[0];
        const tokenRes = await query(
            `SELECT count(*) FROM visits WHERE tenant_id = $1 AND DATE(created_at) = $2`,
            [tenantId, todayStr]
        );
        const tokenNum = parseInt(tokenRes.rows[0].count) + 1;
        const tokenStr = `#${tokenNum.toString().padStart(3, '0')}`;

        // Insert Visit
        const insertVisit = await query(
            `INSERT INTO visits (tenant_id, patient_id, token_number, type, status, fee)
             VALUES ($1, $2, $3, 'walk-in', 'waiting', $4) RETURNING *`,
            [tenantId, patientId, tokenStr, fee || 0]
        );

        await query('COMMIT');
        res.json({ success: true, visit: insertVisit.rows[0], token: tokenStr });
    } catch (err) {
        await query('ROLLBACK');
        console.error('[Clinic Walk-in]', err);
        res.status(500).json({ error: 'Failed to register walk-in' });
    }
});

// ── CLINIC OWNER ROUTES ───────────────────────────────────────────────────────

/**
 * PATCH /api/clinic/settings  — clinic owner updates own settings
 */
app.patch('/api/clinic/settings', requireAuth('OWNER'), async (req, res) => {
    const { consultationFee, workingHours, daysOff, holidays, primaryColor, secondaryColor, servicesCatalog } = req.body;
    const tenantId = req.user.tenantId;

    try {
        const fields = [];
        const values = [];
        let i = 1;

        if (consultationFee !== undefined) { fields.push(`consultation_fee=$${i++}`); values.push(consultationFee); }
        if (primaryColor !== undefined)    { fields.push(`primary_color=$${i++}`);    values.push(primaryColor); }
        if (secondaryColor !== undefined)  { fields.push(`secondary_color=$${i++}`);  values.push(secondaryColor); }
        if (workingHours !== undefined)    { fields.push(`working_hours=$${i++}::jsonb`); values.push(JSON.stringify(workingHours)); }
        if (daysOff !== undefined)         { fields.push(`days_off=$${i++}::jsonb`);   values.push(JSON.stringify(daysOff)); }
        if (holidays !== undefined)        { fields.push(`holidays=$${i++}::jsonb`);   values.push(JSON.stringify(holidays)); }
        if (servicesCatalog !== undefined) { fields.push(`services_catalog=$${i++}::jsonb`); values.push(JSON.stringify(servicesCatalog)); }

        if (fields.length === 0) return res.status(400).json({ error: 'No fields to update' });

        values.push(tenantId);
        await query(`UPDATE tenants SET ${fields.join(',')} WHERE id=$${i}`, values);
        res.json({ success: true });
    } catch (err) {
        console.error('[Clinic Settings]', err);
        res.status(500).json({ error: 'Failed to update settings' });
    }
});

/**
 * PATCH /api/doctor/profile — Doctor updates own profile
 */
app.patch('/api/doctor/profile', requireAuth('DOCTOR'), async (req, res) => {
    const { blockedDates, qAndA } = req.body;
    const userId = req.user.userId;

    try {
        const fields = [];
        const values = [];
        let i = 1;

        if (blockedDates !== undefined) { fields.push(`blocked_dates=$${i++}::jsonb`); values.push(JSON.stringify(blockedDates)); }
        if (qAndA !== undefined) { fields.push(`q_and_a=$${i++}::jsonb`); values.push(JSON.stringify(qAndA)); }

        if (fields.length === 0) return res.status(400).json({ error: 'No fields to update' });

        values.push(userId);
        await query(`UPDATE users SET ${fields.join(',')} WHERE id=$${i}`, values);
        res.json({ success: true });
    } catch (err) {
        console.error('[Doctor Profile]', err);
        res.status(500).json({ error: 'Failed to update profile' });
    }
});

/**
 * POST /api/doctor/upload-media — Upload images/videos to MinIO
 */
app.post('/api/doctor/upload-media', requireAuth('DOCTOR'), upload.single('media'), async (req, res) => {
    if (!req.file) return res.status(400).json({ error: 'No file uploaded' });

    try {
        const userId = req.user.userId;
        const ext = path.extname(req.file.originalname) || '.jpg';
        const fileName = `profile_${userId}_${Date.now()}${ext}`;
        
        const fileUrl = await uploadFile(fileName, req.file.buffer, req.file.mimetype);
        
        // Append to profile_media JSON
        const userRow = await query('SELECT profile_media FROM users WHERE id = $1', [userId]);
        const media = userRow.rows[0].profile_media || {};
        const mediaList = media.uploads || [];
        mediaList.push({ url: fileUrl, type: req.file.mimetype, name: req.file.originalname });
        
        await query('UPDATE users SET profile_media = $1::jsonb WHERE id = $2', [JSON.stringify({ uploads: mediaList }), userId]);
        
        res.json({ success: true, url: fileUrl });
    } catch (err) {
        console.error('[Media Upload]', err);
        res.status(500).json({ error: 'Failed to upload media' });
    }
});

// ── RAZORPAY PAYMENTS ─────────────────────────────────────────────────────────

app.post('/api/payments/create-order', requireAuth(), async (req, res) => {
    const { amount, currency = 'INR', notes } = req.body;
    
    if (!amount) return res.status(400).json({ error: 'Amount is required' });

    try {
        const options = {
            amount: amount * 100, // Razorpay works in smallest currency unit (paise)
            currency,
            receipt: `rcpt_${Date.now()}`,
            notes,
        };
        
        const order = await razorpayInstance.orders.create(options);
        
        // Save transaction to DB
        await query(
            `INSERT INTO transactions (order_id, amount, currency, tenant_id, user_id)
             VALUES ($1, $2, $3, $4, $5)`,
            [order.id, amount, currency, req.user.tenantId, req.user.userId]
        );

        res.json({ success: true, orderId: order.id, amount: order.amount, currency: order.currency });
    } catch (err) {
        console.error('[Create Order Error]', err);
        res.status(500).json({ error: 'Failed to create payment order' });
    }
});

app.post('/api/payments/verify', requireAuth(), async (req, res) => {
    const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;

    const secret = process.env.RAZORPAY_KEY_SECRET || 'dummy_secret_key';
    const body = razorpay_order_id + '|' + razorpay_payment_id;
    
    const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(body.toString())
        .digest('hex');

    if (expectedSignature === razorpay_signature) {
        // Mark as paid
        await query('UPDATE transactions SET status = $1, payment_id = $2 WHERE order_id = $3', 
            ['PAID', razorpay_payment_id, razorpay_order_id]);
            
        res.json({ success: true });
    } else {
        res.status(400).json({ error: 'Invalid signature' });
    }
});


// ── WHATSAPP WEBHOOK ──────────────────────────────────────────────────────────

// Using twilio.webhook() middleware for request validation
// Disable validation in local environment to allow testing via ngrok/local tools
const shouldValidate = process.env.NODE_ENV === 'production';
app.post('/whatsapp/webhook', twilio.webhook({ validate: shouldValidate }), async (req, res) => {
    const from = req.body.From || req.body.from;
    const to = req.body.To || req.body.to;
    const body = req.body.Body || req.body.body;

    console.log(`[WhatsApp Webhook] Received message from ${from} to ${to}: ${body}`);
    if (!from || !body) return res.status(400).send('Missing from or body');

    try {
        const temporalClient = await getTemporalClient();
        const workflowId = `booking-${from.replace(/[^a-zA-Z0-9]/g, '')}`;

        let handle;
        try {
            handle = temporalClient.workflow.getHandle(workflowId);
            const desc = await handle.describe();
            if (desc.status.name === 'RUNNING') {
                await handle.signal('receive_message', body);
                return res.type('text/xml').send('<Response></Response>');
            }
        } catch (err) { /* start new */ }

        await temporalClient.workflow.start('AppointmentBookingWorkflow', {
            args: [body, from, to], taskQueue: 'curaflow-tasks', workflowId,
        });
        res.type('text/xml').send('<Response></Response>');
    } catch (err) {
        console.error('[WhatsApp Webhook] Temporal unavailable, falling back to local botLogic. Error:', err.message);
        
        // Fallback to local bot logic if Temporal is not running
        try {
            const botResponse = await botLogic.handleMessage(from, body);
            let replyText = botResponse.reply;
            
            // Format buttons for standard WhatsApp text since we aren't using Twilio Content Templates
            if (botResponse.buttons && botResponse.buttons.length > 0) {
                replyText += '\n\n' + botResponse.buttons.map((b, i) => `${i + 1}. ${b}`).join('\n');
            }
            
            await whatsappService.sendWhatsApp(from, replyText);
            res.type('text/xml').send('<Response></Response>');
        } catch (botErr) {
            console.error('[WhatsApp Webhook] Fallback logic error:', botErr);
            res.status(500).send('Internal Server Error');
        }
    }
});

// ── MANUAL TOKEN NOTIFICATION ──────────────────────────────────────────────────

app.post('/api/whatsapp/send-token', requireAuth(), async (req, res) => {
    const { patientPhone, tokenNumber, clinicName, slotTime, fee } = req.body;
    if (!patientPhone || !tokenNumber || !clinicName || !slotTime) {
        return res.status(400).json({ error: 'Missing required fields' });
    }
    
    try {
        const result = await whatsappService.sendTokenConfirmation(
            patientPhone, 
            tokenNumber, 
            clinicName, 
            slotTime, 
            fee || 0
        );
        if (result.success) {
            res.json({ success: true, sid: result.sid });
        } else {
            res.status(500).json({ error: result.error });
        }
    } catch (err) {
        console.error('[Send Token]', err);
        res.status(500).json({ error: 'Failed to send token via WhatsApp' });
    }
});

// ── AI SCRIBE ─────────────────────────────────────────────────────────────────

app.post('/api/ai/scribe/start', async (req, res) => {
    try {
        const { dictation } = req.body;
        if (!dictation) return res.status(400).json({ error: 'Dictation is required' });
        const temporalClient = await getTemporalClient();
        const jobId = `scribe-${crypto.randomUUID()}`;
        await temporalClient.workflow.start('ClinicalIntakeWorkflow', {
            args: [dictation], taskQueue: 'curaflow-tasks', workflowId: jobId,
        });
        res.json({ success: true, jobId });
    } catch (err) {
        console.error('[AI Scribe] Start Error:', err);
        res.status(500).json({ error: 'Failed to start AI Scribe job' });
    }
});

app.get('/api/ai/scribe/status/:jobId', async (req, res) => {
    try {
        const temporalClient = await getTemporalClient();
        const handle = temporalClient.workflow.getHandle(req.params.jobId);
        const description = await handle.describe();
        if (description.status.name === 'COMPLETED') {
            return res.json({ status: 'COMPLETED', result: await handle.result() });
        } else if (description.status.name === 'FAILED') {
            return res.json({ status: 'FAILED' });
        }
        res.json({ status: description.status.name });
    } catch (err) {
        console.error('[AI Scribe] Status Error:', err);
        res.status(500).json({ error: 'Failed to get job status' });
    }
});

// ── LAB WATCHER ───────────────────────────────────────────────────────────────

app.post('/api/ai/lab/watch/start', async (req, res) => {
    try {
        const { patientId, baselineData } = req.body;
        if (!patientId) return res.status(400).json({ error: 'Patient ID is required' });
        const temporalClient = await getTemporalClient();
        const workflowId = `lab-watcher-${patientId}`;
        try {
            const handle = temporalClient.workflow.getHandle(workflowId);
            const desc = await handle.describe();
            if (desc.status.name === 'RUNNING') return res.json({ success: true, message: 'Watcher already running' });
        } catch (e) { /* start new */ }
        await temporalClient.workflow.start('LabResultWatcherWorkflow', {
            args: [baselineData || { baseline: 'Patient is healthy', medications: [] }],
            taskQueue: 'curaflow-tasks', workflowId,
        });
        res.json({ success: true });
    } catch (err) {
        console.error('[AI Lab Watcher] Start Error:', err);
        res.status(500).json({ error: 'Failed to start AI Lab Watcher' });
    }
});

app.post('/api/ai/lab/result/:patientId', async (req, res) => {
    try {
        const { result } = req.body;
        if (!result) return res.status(400).json({ error: 'Lab result string is required' });
        const temporalClient = await getTemporalClient();
        const handle = temporalClient.workflow.getHandle(`lab-watcher-${req.params.patientId}`);
        await handle.signal('add_lab_result', result);
        res.json({ success: true });
    } catch (err) {
        console.error('[AI Lab Watcher] Signal Error:', err);
        res.status(500).json({ error: 'Failed to send lab result to AI Watcher' });
    }
});

app.get('/api/ai/lab/alerts/:patientId', async (req, res) => {
    try {
        const temporalClient = await getTemporalClient();
        try {
            const handle = temporalClient.workflow.getHandle(`lab-watcher-${req.params.patientId}`);
            const alerts = await handle.query('get_alerts');
            return res.json({ success: true, alerts });
        } catch (e) {
            res.json({ success: true, alerts: [] });
        }
    } catch (err) {
        console.error('[AI Lab Watcher] Query Error:', err);
        res.status(500).json({ error: 'Failed to fetch alerts' });
    }
});

// ── Prescriptions API ─────────────────────────────────────────────────────────

app.post('/api/prescriptions', requireAuth('DOCTOR'), async (req, res) => {
    try {
        const { patientId, patientName, diagnosis, medicines, labTests } = req.body;
        const tenantId = req.user.tenantId;
        const doctorId = req.user.id;
        
        const result = await prescriptionManager.generate(tenantId, doctorId, patientId, patientName, diagnosis, medicines, labTests);
        
        // Push notification via whatsappService (optional)
        if (whatsappService && whatsappService.sendMessage && req.body.patientPhone) {
            await whatsappService.sendMessage(req.body.patientPhone, result.whatsappMessage);
        }

        res.json(result);
    } catch (error) {
        console.error('[Prescription API] Error:', error);
        res.status(500).json({ error: 'Failed to create prescription' });
    }
});

app.get('/api/prescriptions/pending', requireAuth(), async (req, res) => {
    try {
        const tenantId = req.user.tenantId;
        const pending = await prescriptionManager.getPending(tenantId);
        res.json({ success: true, prescriptions: pending });
    } catch (error) {
        console.error('[Prescription API] Error:', error);
        res.status(500).json({ error: 'Failed to fetch pending prescriptions' });
    }
});

app.post('/api/prescriptions/:id/status', requireAuth(), async (req, res) => {
    try {
        const tenantId = req.user.tenantId;
        const { status } = req.body;
        const updated = await prescriptionManager.updateStatus(tenantId, req.params.id, status);
        if (!updated) {
            return res.status(404).json({ error: 'Prescription not found' });
        }
        res.json({ success: true, prescription: updated });
    } catch (error) {
        console.error('[Prescription API] Error:', error);
        res.status(500).json({ error: 'Failed to update prescription status' });
    }
});

// ── START ─────────────────────────────────────────────────────────────────────

initSchema().then(() => {
    initStorage().then(() => {
        app.listen(port, '0.0.0.0', () => {
            console.log(`Curio HMS running at http://0.0.0.0:${port}`);
        });
    });
});
