// src/routes/health.routes.ts
import { Router, Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { checkTablesExist, getPoolStatus } from '../services/db/connection.db';
import { logger } from '../services/logger.server';
import { connection as redisConnection } from '../services/queueService.server';
import fs from 'node:fs/promises';
import { getSimpleWeekAndYear } from '../utils/dateUtils';
import { validateRequest } from '../middleware/validation.middleware';

const router = Router();

// --- Zod Schemas for Health Routes (as per ADR-003) ---
// These routes do not expect any input, so we define empty schemas
// to maintain a consistent validation pattern across the application.
const emptySchema = z.object({});

/**
 * GET /api/health/ping - A simple endpoint to check if the server is responsive.
 */
router.get('/ping', validateRequest(emptySchema), (_req: Request, res: Response) => {
    res.status(200).send('pong');
});

/**
 * GET /api/health/db-schema - Checks if all essential database tables exist.
 * This is a critical check to ensure the database schema is correctly set up.
 */
router.get('/db-schema', validateRequest(emptySchema), async (req, res, next: NextFunction) => {
    try {
        const requiredTables = ['users', 'profiles', 'flyers', 'flyer_items', 'stores'];
        const missingTables = await checkTablesExist(requiredTables);

        if (missingTables.length > 0) {
            // Create a new error to be handled by the global error handler
            return next(new Error(`Database schema check failed. Missing tables: ${missingTables.join(', ')}.`));
        }
        return res.status(200).json({ success: true, message: 'All required database tables exist.' });
    } catch (error: unknown) {
        logger.error({ error: error instanceof Error ? error.message : error }, 'Error during DB schema check:');
        next(error);
    }
});

/**
 * GET /api/health/storage - Verifies that the application's file storage path is accessible and writable.
 * This is important for features like file uploads.
 */
router.get('/storage', validateRequest(emptySchema), async (req, res, next: NextFunction) => {
    const storagePath = process.env.STORAGE_PATH || '/var/www/flyer-crawler.projectium.com/assets';
    try {
        await fs.access(storagePath, fs.constants.W_OK); // Use fs.promises
        return res.status(200).json({ success: true, message: `Storage directory '${storagePath}' is accessible and writable.` });
    } catch (error: unknown) {
        logger.error({ error: error instanceof Error ? error.message : error }, `Storage check failed for path: ${storagePath}`);
        next(new Error(`Storage check failed. Ensure the directory '${storagePath}' exists and is writable by the application.`));
    }
});

/**
 * GET /api/health/db-pool - Checks the status of the database connection pool.
 * This helps diagnose issues related to database connection saturation.
 */
router.get('/db-pool', validateRequest(emptySchema), (req: Request, res: Response, next: NextFunction) => {
    try {
        const status = getPoolStatus();
        const isHealthy = status.waitingCount < 5;
        const message = `Pool Status: ${status.totalCount} total, ${status.idleCount} idle, ${status.waitingCount} waiting.`;
        
        if (isHealthy) {
            return res.status(200).json({ success: true, message });
        } else {
            logger.warn(`Database pool health check shows high waiting count: ${status.waitingCount}`);
            return res.status(500).json({ success: false, message: `Pool may be under stress. ${message}` });
        }
    } catch (error: unknown) {
        logger.error({ error: error instanceof Error ? error.message : error }, 'Error during DB pool health check:');
        next(error);
    }
});

/**
 * GET /api/health/time - Returns the server's current time, year, and week number.
 * Useful for verifying time synchronization and for features dependent on week numbers.
 */
router.get('/time', validateRequest(emptySchema), (req: Request, res: Response) => {
    const now = new Date();
    const { year, week } = getSimpleWeekAndYear(now);
    res.json({
        currentTime: now.toISOString(),
        year,
        week,
    });
});

/**
 * GET /api/health/redis - Checks the health of the Redis connection.
 */
router.get('/redis', validateRequest(emptySchema), async (req: Request, res: Response, next: NextFunction) => {
    try {
        const reply = await redisConnection.ping();
        if (reply === 'PONG') {
            return res.status(200).json({ success: true, message: 'Redis connection is healthy.' });
        }
        throw new Error(`Unexpected Redis ping response: ${reply}`); // This will be caught below
    } catch (error: unknown) {
        next(error);
    }
});

export default router;