import type { Express, Request, Response } from "express";
import express, { Router } from "express";
import { readdirSync, readFileSync, statSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import crypto from "crypto";
import fs from "fs";

export const setupMobileRoutes = (app: Express, basePath: string) => {
    const router = Router();
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    const distPath = join(__dirname, "../../../../mobileLst/dist");

    function generateAssetManifest(baseUrl: string) {
        const assets: any[] = [];
        const assetsDir = join(distPath, "assets");

        try {
            if (!fs.existsSync(assetsDir)) {
                return assets;
            }

            const files = readdirSync(assetsDir);
            files.forEach((file) => {
                const filePath = join(assetsDir, file);
                const stats = statSync(filePath);

                if (stats.isFile()) {
                    const content = readFileSync(filePath);
                    const hash = crypto
                        .createHash("sha256")
                        .update(content)
                        .digest("hex");

                    assets.push({
                        hash: hash,
                        key: file,
                        fileExtension: `.${file.split(".").pop()}`,
                        contentType: getContentType(file),
                        url: `${baseUrl}/assets/${file}`,
                    });
                }
            });
        } catch (err) {
            console.log("Error reading assets:", err);
        }

        return assets;
    }

    function getContentType(filename: string): string {
        const ext = filename.split(".").pop()?.toLowerCase();
        const contentTypes: { [key: string]: string } = {
            hbc: "application/javascript",
            bundle: "application/javascript",
            js: "application/javascript",
            json: "application/json",
            png: "image/png",
            jpg: "image/jpeg",
            jpeg: "image/jpeg",
            gif: "image/gif",
            ttf: "font/ttf",
            otf: "font/otf",
            woff: "font/woff",
            woff2: "font/woff2",
        };
        return contentTypes[ext || ""] || "application/octet-stream";
    }

    app.get(basePath + "/api/mobile/updates", (req, res) => {
        console.log("=== OTA Update Request ===");
        console.log("Headers:", JSON.stringify(req.headers, null, 2));

        const runtimeVersion = req.headers["expo-runtime-version"];
        const platform = req.headers["expo-platform"] || "android";
        const expectedRuntimeVersion = "1.0.0";

        if (runtimeVersion !== expectedRuntimeVersion) {
            console.log(
                `Runtime mismatch: got ${runtimeVersion}, expected ${expectedRuntimeVersion}`
            );
            return res.status(404).json({
                error: "No update available for this runtime version",
                requestedVersion: runtimeVersion,
                availableVersion: expectedRuntimeVersion,
            });
        }

        try {
            // const host = req.get('host');
            // // If it's the production domain, force https
            // const protocol = host.includes('alpla.net') ? 'https' : req.protocol;

            // const baseUrl = `${protocol}://${host}/lst/api/mobile/updates`

            const host = req.get('host');  // Should be "usmcd1vms036:4000"
            const protocol = 'http';
            const baseUrl = `${protocol}://${host}/api/mobile/updates`;

            // Find the .hbc file
            const bundleDir = join(distPath, "_expo/static/js/android");

            if (!fs.existsSync(bundleDir)) {
                console.error("Bundle directory does not exist:", bundleDir);
                return res
                    .status(500)
                    .json({ error: "Bundle directory not found" });
            }

            const bundleFiles = readdirSync(bundleDir);
            console.log("Available bundle files:", bundleFiles);

            const bundleFile = bundleFiles.find((f) => f.endsWith(".hbc"));

            if (!bundleFile) {
                console.error("No .hbc file found in:", bundleDir);
                return res
                    .status(500)
                    .json({ error: "Hermes bundle (.hbc) not found" });
            }

            console.log("Using bundle file:", bundleFile);

            const bundlePath = join(bundleDir, bundleFile);
            const bundleContent = readFileSync(bundlePath);
            const bundleHash = crypto
                .createHash("sha256")
                .update(bundleContent)
                .digest("hex");

            const updateId = crypto.randomUUID();
            const createdAt = new Date().toISOString();

            // This is the NEW manifest format for Expo SDK 50+
            const manifest = {
                id: updateId,
                createdAt: createdAt,
                runtimeVersion: expectedRuntimeVersion,
                launchAsset: {
                    hash: bundleHash,
                    key: bundleFile,
                    contentType: "application/javascript",
                    fileExtension: ".hbc",
                    url: `${baseUrl}/_expo/static/js/android/${bundleFile}`,
                },
                assets: generateAssetManifest(baseUrl),
                metadata: {},
                extra: {
                    expoClient: {
                        name: "LSTScanner",
                        slug: "lst-scanner-app",
                        version: "1.0.0",
                        runtimeVersion: expectedRuntimeVersion,
                    },
                },
            };

            console.log(
                "Returning manifest:",
                JSON.stringify(manifest, null, 2)
            );

            res.setHeader("Content-Type", "application/json");
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.setHeader("expo-protocol-version", "1");
            res.setHeader("expo-sfv-version", "0");
            res.json(manifest);
        } catch (error: any) {
            console.error("Error generating manifest:", error);
            res.status(500).json({
                error: "Failed to generate manifest",
                details: error.message,
                stack: error.stack,
            });
        }
    });

    // Serve static files
    app.use(
        basePath + "/api/mobile/updates",
        express.static(distPath, {
            setHeaders(res, path) {
                res.setHeader("Access-Control-Allow-Origin", "*");
                res.setHeader("Cache-Control", "public, max-age=31536000");

                if (path.endsWith(".hbc")) {
                    res.setHeader("Content-Type", "application/javascript");
                }
            },
        })
    );
    // app.use(
    //     basePath + "/api/mobile/updates",
    //     express.static(join(__dirname, mobileDir), {
    //         setHeaders(res) {
    //             // OTA runtime needs to fetch these from the device
    //             console.log("OTA check called");
    //             res.setHeader("Access-Control-Allow-Origin", "*");
    //         },
    //     })
    // );

    // app.get(basePath + "/api/mobile/updates", (req, res) => {
    //     res.redirect(basePath + "/api/mobile/updates/metadata.json");
    // });

    app.get(basePath + "/api/mobile", (_, res) =>
        res.status(200).json({ message: "LST OTA server is up." })
    );
};
