import { Router } from "express";
import { verifyStreamlineToken } from "./streamlineAuthVerify.js";
import { serverLogger } from "../utils/serverLogger.js";
import { getDatabase } from "./database.js";
import { playerWebSocket } from "./playerWebSocket.js";
import { getUserByApiKey, hasFamilySharingTables } from "./migrations/addFamilySharing.js";
/**
 * Create Wave integration routes
 * These routes handle the connection between Wave and SOUND
 */ export function createWaveIntegrationRoutes(appState) {
    const router = Router();
    /**
   * Public endpoint for Wave to check if SOUND is running
   * No authentication required
   */ router.get("/api/wave/ping", (req, res)=>{
        res.json({
            running: true,
            requiresAuth: true,
            hasStreamlineSupport: true,
            version: process.env.npm_package_version || "1.0.0",
            server: "SOUND",
            timestamp: Date.now()
        });
    });
    /**
   * Wave connection endpoint - Simple auth: auto-trust localhost, require API key for remote
   */ router.get("/api/wave/connect", async (req, res)=>{
        try {
            const db = getDatabase();
            const stats = db.getStats();
            const tunnelConfig = await appState.getTunnelConfig();
            // Get client IP
            const clientIp = req.ip || req.socket.remoteAddress || '';
            const isLocalhost = clientIp === '127.0.0.1' || clientIp === '::1' || clientIp === '::ffff:127.0.0.1' || clientIp.startsWith('127.');
            serverLogger.info("WAVE connect request", {
                clientIp,
                isLocalhost,
                hasApiKey: !!appState.getApiKey()
            });
            // Auto-trust localhost connections
            if (isLocalhost) {
                serverLogger.info("WAVE connected from localhost - auto-trusted");
                return res.json({
                    success: true,
                    sound: {
                        apiKey: appState.getApiKey(),
                        tracks: stats.total || 0,
                        tunnelActive: !!tunnelConfig,
                        externalUrl: tunnelConfig?.hostname || undefined
                    }
                });
            }
            // For remote connections, require API key in header
            const providedApiKey = req.headers['x-api-key'];
            const serverApiKey = appState.getApiKey();
            if (!providedApiKey) {
                return res.status(401).json({
                    error: "API key required for remote connections",
                    message: "Copy your API key from SOUND settings"
                });
            }
            // Check if it's the owner's API key
            if (providedApiKey === serverApiKey) {
                serverLogger.info("WAVE connected from remote with owner API key", {
                    clientIp
                });
                return res.json({
                    success: true,
                    sound: {
                        apiKey: serverApiKey,
                        tracks: stats.total || 0,
                        tunnelActive: !!tunnelConfig,
                        externalUrl: tunnelConfig?.hostname || undefined
                    }
                });
            }
            // Check if it's a family member's API key
            if (db?.db && hasFamilySharingTables(db.db)) {
                const user = getUserByApiKey(db.db, providedApiKey);
                if (user) {
                    serverLogger.info("WAVE connected from remote with family member API key", {
                        clientIp,
                        userId: user.id,
                        userName: user.name,
                        isOwner: user.is_owner
                    });
                    // CRITICAL: Return the family member's OWN API key, not the owner's
                    // This ensures per-user play history filtering works correctly
                    return res.json({
                        success: true,
                        sound: {
                            apiKey: providedApiKey,
                            tracks: stats.total || 0,
                            tunnelActive: !!tunnelConfig,
                            externalUrl: tunnelConfig?.hostname || undefined
                        }
                    });
                }
            }
            // Invalid API key
            serverLogger.warn("WAVE connect failed - invalid API key", {
                clientIp
            });
            return res.status(401).json({
                error: "Invalid API key",
                message: "The API key doesn't match this SOUND server"
            });
        } catch (error) {
            serverLogger.error("WAVE connect error", {
                error
            });
            return res.status(500).json({
                error: "Connection failed"
            });
        }
    });
    /**
   * Endpoint to manually link SOUND with a Streamline account
   */ router.post("/api/streamline/link", async (req, res)=>{
        try {
            const { streamlineToken, userInfo } = req.body;
            if (!streamlineToken) {
                return res.status(400).json({
                    error: "Streamline token required",
                    message: "Please provide a valid Streamline token"
                });
            }
            // Verify the Streamline token
            const user = await verifyStreamlineToken(streamlineToken, appState);
            if (!user) {
                return res.status(401).json({
                    error: "Invalid Streamline token",
                    message: "The provided Streamline token is invalid or expired"
                });
            }
            // Get and update configuration
            const config = appState.getConfig();
            // Check if already linked to a different user
            if (config.waveAuth?.user_id && config.waveAuth.user_id !== user.sub) {
                return res.status(409).json({
                    error: "SOUND is already linked to another account",
                    message: `This SOUND instance is already linked to ${config.waveAuth.email}`,
                    linkedEmail: config.waveAuth.email
                });
            }
            // Save the Streamline user info
            const waveAuth = {
                access_token: streamlineToken,
                user_id: user.sub,
                email: user.email,
                expires_at: user.exp,
                linked_at: Date.now(),
                refresh_token: userInfo?.refresh_token || ""
            };
            appState.saveWaveAuth(waveAuth);
            serverLogger.info("Linked SOUND to Streamline account", {
                userId: user.sub,
                email: user.email
            });
            res.json({
                success: true,
                message: "SOUND linked to Streamline account",
                apiKey: config.apiKey || appState.getApiKey(),
                user: {
                    id: user.sub,
                    email: user.email
                }
            });
        } catch (error) {
            serverLogger.error("Failed to link Streamline account", {
                error
            });
            res.status(500).json({
                error: "Failed to link Streamline account",
                message: error.message
            });
        }
    });
    /**
   * Endpoint to unlink SOUND from Streamline
   */ router.post("/api/streamline/unlink", async (req, res)=>{
        try {
            const config = appState.getConfig();
            if (!config.waveAuth) {
                return res.status(404).json({
                    error: "Not linked",
                    message: "SOUND is not linked to any Streamline account"
                });
            }
            const previousEmail = config.waveAuth.email;
            appState.clearWaveAuth();
            serverLogger.info("Unlinked SOUND from Streamline account", {
                previousEmail
            });
            res.json({
                success: true,
                message: "SOUND unlinked from Streamline account",
                previousEmail
            });
        } catch (error) {
            serverLogger.error("Failed to unlink Streamline account", {
                error
            });
            res.status(500).json({
                error: "Failed to unlink Streamline account",
                message: error.message
            });
        }
    });
    /**
   * Get current link status
   */ router.get("/api/streamline/status", (req, res)=>{
        const config = appState.getConfig();
        res.json({
            linked: !!config.waveAuth,
            user: config.waveAuth ? {
                id: config.waveAuth.user_id,
                email: config.waveAuth.email,
                linkedAt: config.waveAuth.linked_at
            } : null
        });
    });
    /**
   * Update track metadata
   * PATCH /api/wave/tracks/metadata
   */ router.patch("/api/wave/tracks/metadata", async (req, res)=>{
        try {
            const { file_path, updates } = req.body;
            if (!file_path || !updates) {
                return res.status(400).json({
                    error: "Missing file_path or updates in request body"
                });
            }
            // Validate that at least one field is being updated
            const allowedFields = [
                'title',
                'artist',
                'album',
                'track_number',
                'year'
            ];
            const updateKeys = Object.keys(updates);
            const invalidFields = updateKeys.filter((key)=>!allowedFields.includes(key));
            if (invalidFields.length > 0) {
                return res.status(400).json({
                    error: `Invalid fields: ${invalidFields.join(', ')}`
                });
            }
            if (updateKeys.length === 0) {
                return res.status(400).json({
                    error: "No fields to update"
                });
            }
            // Build UPDATE query dynamically
            const db = getDatabase();
            const fields = [];
            const values = [];
            // Map frontend field names to database column names
            const fieldMapping = {
                'title': 'title',
                'artist': 'artist',
                'album': 'album',
                'track_number': 'track_no',
                'year': 'year'
            };
            for (const [key, value] of Object.entries(updates)){
                if (value !== undefined && allowedFields.includes(key)) {
                    const dbField = fieldMapping[key];
                    fields.push(`${dbField} = ?`);
                    values.push(value);
                }
            }
            // Add file_path to values for WHERE clause
            values.push(file_path);
            const query = `UPDATE tracks SET ${fields.join(', ')} WHERE path = ?`;
            serverLogger.info("Updating track metadata", {
                file_path,
                updates,
                query
            });
            // Execute update
            db.db.prepare(query).run(...values);
            const updatedTrack = db.db.prepare('SELECT * FROM tracks WHERE path = ?').get(file_path);
            if (!updatedTrack) {
                return res.status(404).json({
                    error: "Track not found after update"
                });
            }
            serverLogger.info("Track metadata updated successfully", {
                file_path,
                title: updatedTrack.title
            });
            // Broadcast metadata.updated event via WebSocket to all clients
            playerWebSocket.broadcast({
                type: "metadata.updated",
                data: {
                    path: file_path,
                    track: updatedTrack,
                    timestamp: Date.now()
                }
            }, "metadata");
            serverLogger.info("Broadcasted metadata.updated event to clients");
            res.json({
                success: true,
                track: updatedTrack
            });
        } catch (error) {
            serverLogger.error("Failed to update track metadata", {
                error
            });
            res.status(500).json({
                error: "Failed to update track metadata",
                message: error instanceof Error ? error.message : String(error)
            });
        }
    });
    return router;
}

//# sourceMappingURL=waveIntegrationRoutes.js.map