import express from "express";
import cors from "cors";
import dotenv from "dotenv";
dotenv.config();
import fs from "fs";
import path from "path";
import { notFound } from "./middlewares/notFound";
import { errorHandler } from "./core/errorHandler";
import {
    ensurePersistentStaticDirectories,
    STATIC_APK_DIR,
    STATIC_ASSETS_DIR,
    STATIC_UPLOADS_DIR,
    STATIC_SOUNDS_DIR,
} from "./core/storage-paths";

import categoryRoutes from "./modules/category/category.routes";
import productRoutes from "./modules/product/product.routes";
import orderRoutes from "./modules/order/admin/order.routes";
import posOrderRoutes from "./modules/order/pos/order.routes";
import adminAuthRoutes from "./modules/auth/admin-auth.routes";
import posAuthRoutes from "./modules/auth/pos-auth.routes";
import shopRoutes from "./modules/shop/shop.routes";
import stationRoutes from "./modules/station/station.routes";
import paymentRoutes from "./modules/payment/payment.routes";
import orderItemRoutes from "./modules/orderItem/orderItem.routes";
import cashSessionRoutes from "./modules/cashSession/cashSession.routes";
import sumupRoutes from "./modules/sumup/sumup.routes";
import uploadRoutes from "./modules/upload/upload.routes";
import promoCodeRoutes from "./modules/promoCode/promoCode.routes";
import ingredientRoutes from "./modules/ingredient/ingredient.routes";
import recipeRoutes from "./modules/recipe/recipe.routes";
import productConfiguratorRoutes from "./modules/productConfigurator/product-configurator.routes";
import logisticsRouteRoutes from "./modules/logisticsRoute/logisticsRoute.routes";
import versionRoutes from "./modules/version/version.routes";
import stationSoundRoutes from "./modules/station-sound/station-sound.routes";
import pushRoutes from "./modules/push/push.routes";
import {createHttpLatency} from "./middlewares/latency.http";
import {io} from "@/server";

const app = express();
app.set("trust proxy", 1);
ensurePersistentStaticDirectories();

const uploadsApiStatic = express.static(STATIC_UPLOADS_DIR);
const soundsApiStatic = express.static(STATIC_SOUNDS_DIR);

app.use(
    "/apk",
    express.static(STATIC_APK_DIR)
);

// Expose aussi les APK sur /api/apk (route publique)
app.use(
    "/api/apk",
    express.static(STATIC_APK_DIR)
);

app.use(
    "/assets",
    express.static(STATIC_ASSETS_DIR)
);

// Correction : expose aussi les assets sur /api/assets (route publique)
app.use(
    "/api/assets",
    express.static(STATIC_ASSETS_DIR)
);

app.use(
    "/uploads",
    express.static(STATIC_UPLOADS_DIR)
);

app.use("/api/uploads", (req, res, next) => {
    if (req.method !== "GET" && req.method !== "HEAD") {
        return next();
    }

    return uploadsApiStatic(req, res, () => {
        res.status(404).end();
    });
});

app.use(
    "/sounds",
    express.static(STATIC_SOUNDS_DIR)
);

app.use("/api/sounds", (req, res, next) => {
    if (req.method !== "GET" && req.method !== "HEAD") {
        return next();
    }

    return soundsApiStatic(req, res, () => {
        res.status(404).end();
    });
});

// expose route name and url berfore each request
app.use((req, res, next) => {
    console.log(`[${req.method}] ${req.url}`);
    next();
});

app.use(createHttpLatency(process.env.NETWORK_PROFILE))
app.use(cors());
app.use(express.json());

// ─────────────────────────────────────────────────────────────
// Routes publiques sans auth.
// Enregistrées AVANT les routers `/api/*` qui appliquent `protect`
// globalement via `router.use(protect)` (paymentRoutes, cashSessionRoutes,
// promoCodeRoutes…). Si on les déclare après, leur middleware `protect`
// capte la requête et renvoie 401.
// ─────────────────────────────────────────────────────────────
app.use("/api/version", versionRoutes)

app.get("/api/health", (req, res) => {
    res.json({ status: "ok" });
});

import crypto from "crypto"

const checkUpdateLegacy = (req: any, res: any) => {

    const apkDir = STATIC_APK_DIR;

    // Log détaillé pour debug protocole et headers
    console.log('--- DEBUG checkUpdateLegacy ---');
    console.log('process.env.APK_URL_PROTOCOL =', process.env.APK_URL_PROTOCOL);
    console.log('req.protocol =', req.protocol);
    console.log('req.headers["x-forwarded-proto"] =', req.headers["x-forwarded-proto"]);
    console.log('req.headers =', req.headers);
    console.log(`Checking for updates in ${apkDir}`);

    if (!fs.existsSync(apkDir)) {
        return res.status(404).json({
            error: "No APK found on " + apkDir,
            version: 0,
            apk_url: null,
            checksum: null
        });
    }

    const files = fs.readdirSync(apkDir);
    const versions = files
        .map(f => {
            const match = f.match(/ttm-pos-v(\d+\.?\d*\.?\d*)\.apk/i);
            return match ? {
                file: f,
                version: parseInt(match[1].split('.')[0]),
            } : null;
        })
        .filter(v => v !== null);

    if (versions.length === 0) {
        return res.status(404).json({
            error: "No APK found",
            version: 0,
            apk_url: null,
            checksum: null
        });
    }

    const latest = versions.reduce((max, current) =>
        current.version > max.version ? current : max
    );

    const apkPath = path.join(apkDir, latest.file);
    let checksum: string | null = null;
    try {
        const fileBuffer = fs.readFileSync(apkPath);
        const hashSum = crypto.createHash("sha256");
        hashSum.update(fileBuffer);
        checksum = "sha256:" + hashSum.digest("hex");
        console.log(`✅ Checksum calculated for ${latest.file}: ${checksum}`);
    } catch (error) {
        console.error(`❌ Error calculating checksum: ${String(error)}`);
        checksum = null;
    }

    // Utilise APK_URL_PROTOCOL si défini, sinon req.protocol
    const protocol = process.env.APK_URL_PROTOCOL || req.protocol;
    res.json({
        version: latest.version,
        apk_url: `${protocol}://${req.get("host")}/apk/${latest.file}`,
        checksum,
        size: fs.statSync(apkPath).size,
        timestamp: new Date().toISOString()
    });
}

// Endpoint consommé par l'app Android pour détecter les mises à jour APK.
app.get("/api/apk/check-update", checkUpdateLegacy);
app.get("/apk/check-update", checkUpdateLegacy);

// Route de test (dev) : émet un event socket factice vers le terminal Android.
app.get("/api/pay", (req, res) => {
    io.to("android_terminal").emit("payment_request", {
        amount: 100,
        orderId: Math.random().toString(36).substring(2, 15)
            + Math.random().toString(36).substring(2, 15),
    });
    res.send("payment sent");
});

// Extraire le socket ID de l'émetteur (pour exclure du broadcast WS)
app.use((req, _res, next) => {
    const socketId = req.headers["x-socket-id"] as string | undefined;
    if (socketId) {
        req.senderSocketId = socketId;
    }
    next();
});

import { protect } from "./middlewares/auth.middleware";
import { requireAdmin } from "./middlewares/auth/requireAdmin";
import { getMyShopUsers } from "./modules/shop-user/shop-user.controller";

app.use("/api/auth/admin", adminAuthRoutes);
app.use("/api/auth/pos", posAuthRoutes);


// Route /me — resources liées à l'utilisateur connecté
app.get("/api/me/shop-users", protect, requireAdmin, getMyShopUsers);

// Admin shop-scoped APIs (univers dédié shop)
app.use("/api/shops/:shopId/categories", categoryRoutes);
app.use("/api/shops/:shopId/products", productRoutes);
app.use("/api/shops/:shopId/orders", orderRoutes);
app.use("/api/shops/:shopId/stations", stationRoutes);
app.use("/api/shops/:shopId/stations/:stationId/sounds", stationSoundRoutes);
app.use("/api/shops/:shopId/uploads", uploadRoutes);

app.use("/api/shops/:shopId/ingredients", ingredientRoutes);
app.use("/api/shops/:shopId/recipes", recipeRoutes);
app.use("/api/shops/:shopId/product-configurators", productConfiguratorRoutes);
app.use("/api/shops/:shopId/logistics-routes", logisticsRouteRoutes);
app.use("/api/sumup", sumupRoutes);
app.use("/api/shops", shopRoutes);
app.use("/api/categories", categoryRoutes);
app.use("/api/products", productRoutes);
app.use("/api/orders", orderRoutes);
app.use("/api/orders", posOrderRoutes);
app.use("/api/stations", stationRoutes);
app.use("/api/uploads", uploadRoutes);
app.use("/api/ingredients", ingredientRoutes);
app.use("/api/recipes", recipeRoutes);
app.use("/api/product-configurators", productConfiguratorRoutes);
app.use("/api/order-items", orderItemRoutes);
app.use("/api/push", pushRoutes);
app.use("/api", paymentRoutes);
app.use("/api", cashSessionRoutes);
app.use("/api", promoCodeRoutes);




app.use(notFound);
app.use(errorHandler);

export default app;

