// src/routes/system.ts
import { Router, Request, Response, NextFunction } from 'express';
import { exec } from 'child_process';
import { z } from 'zod';
import { logger } from '../services/logger.server';
import { geocodingService } from '../services/geocodingService.server';
import { validateRequest } from '../middleware/validation.middleware';

const router = Router();

// Helper for consistent required string validation (handles missing/null/empty)
const requiredString = (message: string) => z.preprocess((val) => val ?? '', z.string().min(1, message));

const geocodeSchema = z.object({
  body: z.object({
    address: requiredString('An address string is required.'),
  }),
});

// An empty schema for routes that do not expect any input, to maintain a consistent validation pattern.
const emptySchema = z.object({});

/**
 * Checks the status of the 'flyer-crawler-api' process managed by PM2.
 * This is intended for development and diagnostic purposes.
 */
router.get('/pm2-status', validateRequest(emptySchema), (req: Request, res: Response, next: NextFunction) => {
    // The name 'flyer-crawler-api' comes from your ecosystem.config.cjs file.
    exec('pm2 describe flyer-crawler-api', (error, stdout, stderr) => {
        if (error) {
            // 'pm2 describe' exits with an error if the process is not found.
            // We can treat this as a "fail" status for our check.
            if (stdout && stdout.includes("doesn't exist")) {
                logger.warn('[API /pm2-status] PM2 process "flyer-crawler-api" not found.');
                return res.json({ success: false, message: 'Application process is not running under PM2.' });
            }
            logger.error({ error: stderr || error.message }, '[API /pm2-status] Error executing pm2 describe:');
            return next(error);
        }

        // Check if there was output to stderr, even if the exit code was 0 (success).
        // This handles warnings or non-fatal errors that should arguably be treated as failures in this context.
        if (stderr && stderr.trim().length > 0) {
            logger.error({ stderr }, '[API /pm2-status] PM2 executed but produced stderr:');
            return next(new Error(`PM2 command produced an error: ${stderr}`));
        }

        // If the command succeeds, we can parse stdout to check the status.
        const isOnline = /│ status\s+│ online\s+│/m.test(stdout);
        const message = isOnline ? 'Application is online and running under PM2.' : 'Application process exists but is not online.';
        res.json({ success: isOnline, message });
    });
});

/**
 * POST /api/system/geocode - Geocodes a given address string.
 * This acts as a secure proxy to the Google Maps Geocoding API.
 */
router.post('/geocode', validateRequest(geocodeSchema), async (req: Request, res: Response, next: NextFunction) => {
    // Infer type and cast request object as per ADR-003
    type GeocodeRequest = z.infer<typeof geocodeSchema>;
    const { body: { address } } = req as unknown as GeocodeRequest;

    try {
        const coordinates = await geocodingService.geocodeAddress(address, req.log);

        if (!coordinates) { // This check remains, but now it only fails if BOTH services fail.
            return res.status(404).json({ message: 'Could not geocode the provided address.' });
        }

        res.json(coordinates);
    } catch (error) {
        next(error);
    }
});


export default router;