import http from "http";
import { Server } from "socket.io";
import jwt from "jsonwebtoken";
import { ShopWsEvent, type ShopEventDeliveryAckPayload } from "ttm-shared";
import app from "./app";
//import {orderItemService} from "./modules/orderItem/orderItem.service";
import {applySocketLatency} from "./middlewares/latency.socket";
import { prisma } from "./core/prisma";

const server = http.createServer(app);

export const io = new Server(server, {
    cors: { origin: "*" }
});

applySocketLatency(io, process.env.NETWORK_PROFILE);

// 🔐 Middleware d'auth socket (admin + pos)
io.use((socket, next) => {
    try {
        const token = socket.handshake.auth?.token;

        if (!token) {
            console.log("[ws] Connection attempt without token");
            // On autorise la connexion sans token pour le moment (dev)
            // mais on ne donne pas d'userId
            return next();
        }

        const decoded = jwt.verify(
            token,
            process.env.JWT_SECRET!
        ) as { sub: string; type: "admin" | "pos" };

        (socket as any).userId = decoded.sub;
        (socket as any).authType = decoded.type;

        console.log(`[ws] Authenticated: type=${decoded.type} userId=${decoded.sub}`);

        next();
    } catch(err: any) {
        console.error("[ws] Auth error:", err.message);
        next(new Error("unauthorized"));
    }
});

io.on("connection", (socket) => {
    const userId = (socket as any).userId;
    const authType = (socket as any).authType;

    console.log(`[ws] Socket connected: ${socket.id} (type=${authType}, userId=${userId})`);

    // Auto-join admin room pour recevoir les événements globaux (dashboard)
    if (authType === "admin" && userId) {
        socket.join(`admin:${userId}`);
        console.log(`[ws] ${socket.id} auto-joined admin room admin:${userId}`);
    }

    socket.on("join-shop", (shopId: string) => {
        if (!shopId) return;

        (socket as any).shopId = shopId;
        socket.join(`shop:${shopId}`);
        console.log(`[ws] ${socket.id} joined room shop:${shopId}`);
    });

    socket.on(ShopWsEvent.DELIVERY_ACK, (payload: ShopEventDeliveryAckPayload) => {
        const joinedShopId = (socket as any).shopId as string | undefined;
        if (!payload?.shopId || !payload?.eventId || !payload?.view) {
            return;
        }

        if (!joinedShopId || joinedShopId !== payload.shopId) {
            console.warn(`[ws] Ignored delivery ack from ${socket.id}: socket shop=${joinedShopId ?? "none"} payload shop=${payload.shopId}`);
            return;
        }

        console.log(`[ws] Delivery ack from ${socket.id}: view=${payload.view} event=${payload.eventType} eventId=${payload.eventId}`);
        io.to(`shop:${payload.shopId}`).emit(ShopWsEvent.DELIVERY_ACKNOWLEDGED, payload);
    });


    socket.on("join-station", (stationId: string) => {
        const role = (socket as any).role;

        if (role !== "kitchen" && role !== "admin") {
            return;
        }

        socket.join(`station:${stationId}`);
        console.log("Joined station:", stationId);
    });

    socket.on("disconnect", () => {
        console.log("Socket disconnected:", socket.id);
    });


    console.log("Android connected:", socket.id);

    socket.on("message", (data) => {
        console.log("Message from android:", data);
    });

    socket.on("ping", (data) => {
        console.log("PING from android");
    });

    socket.on("payment_success", (data) => {
        console.log("Payment success from android", data);
    });

    socket.on("payment_failed", (data) => {
        console.log("Payment failed from android", data);
    })


    socket.on("register_device", (deviceId) => {
        socket.join(deviceId)
        console.log("Device registered:", deviceId)
    })

});

const PORT = process.env.PORT || 3000;

server.listen(PORT, async () => {
    console.log(`Server running on port ${PORT}`);

    // Cleanup: marquer les payment attempts PENDING comme FAILED au restart
    // (les pollers sont perdus, les checkouts ont pu expirer)
    try {
        const cleaned = await prisma.paymentAttempt.updateMany({
            where: { status: "PENDING" },
            data: {
                status: "FAILED",
                failureReason: "Server restarted: stale PENDING attempt"
            }
        });
        if (cleaned.count > 0) {
            console.log(`[Startup] Cleaned ${cleaned.count} stale PENDING payment attempts`);
        }
    } catch (err) {
        console.error("[Startup] Failed to cleanup stale payment attempts:", err);
    }
});