const { app, BrowserWindow, ipcMain, desktopCapturer, screen, session, shell } = require('electron');
const path = require('path');
const fs = require('fs');

// Global configuration: change to false for the Paid version build
let IS_FREE_VERSION = true;

function validateLicenseKey(key) {
    if (!key || typeof key !== 'string') return false;
    const cleanKey = key.trim().toUpperCase().replace(/[^A-Z0-9-]/g, '');
    const parts = cleanKey.split('-');
    if (parts.length !== 5) return false;
    if (parts[0] !== 'FMS' || parts[1] !== 'PRO') return false;
    if (parts[2].length !== 4 || parts[3].length !== 4 || parts[4].length !== 4) return false;
    
    const checkString = parts.slice(0, 4).join('-');
    const checksum = parts[4];
    
    let hash = 5381;
    for (let i = 0; i < checkString.length; i++) {
        hash = ((hash << 5) + hash) + checkString.charCodeAt(i);
    }
    const computed = (hash >>> 0).toString(16).toUpperCase().slice(-4);
    
    return computed === checksum;
}

function loadLicense() {
    try {
        const licFile = getLogPath('license.key');
        if (fs.existsSync(licFile)) {
            const key = fs.readFileSync(licFile, 'utf8').trim();
            if (validateLicenseKey(key)) {
                IS_FREE_VERSION = false;
                return true;
            }
        }
    } catch (e) {
        console.error("Failed to load license:", e);
    }
    IS_FREE_VERSION = true;
    return false;
}

app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');

// Get dynamic path for logs, avoiding hardcoded user directories
function getLogPath(filename) {
    try {
        const baseDir = app.isPackaged ? app.getPath('userData') : __dirname;
        return path.join(baseDir, filename);
    } catch (e) {
        return path.join(__dirname, filename);
    }
}

const usageFilePath = getLogPath('license_usage.json');
const FREE_LIMIT_MS = 5 * 60 * 1000; // 5 minutes
const COOLDOWN_DURATION_MS = 60 * 60 * 1000; // 1 hour

let usageState = {
    windowStartTime: 0,
    cumulativeTime: 0,
    cooldownEndTime: 0
};

function loadUsageState() {
    try {
        if (fs.existsSync(usageFilePath)) {
            const data = fs.readFileSync(usageFilePath, 'utf8');
            usageState = JSON.parse(data);
        }
    } catch (e) {
        usageState = { windowStartTime: 0, cumulativeTime: 0, cooldownEndTime: 0 };
    }
}

function saveUsageState() {
    try {
        fs.writeFileSync(usageFilePath, JSON.stringify(usageState, null, 2), 'utf8');
    } catch (e) {
        console.error("Failed to save usage state:", e);
    }
}

function checkFullscreenAllowed() {
    loadUsageState();
    const now = Date.now();

    // 1. If cooldown is active
    if (usageState.cooldownEndTime > now) {
        const remainingMs = usageState.cooldownEndTime - now;
        return { allowed: false, reason: 'cooldown', remainingMs };
    }

    // 2. Reset window if 1 hour has passed since windowStartTime
    if (usageState.windowStartTime > 0 && now - usageState.windowStartTime >= COOLDOWN_DURATION_MS) {
        usageState.windowStartTime = 0;
        usageState.cumulativeTime = 0;
        usageState.cooldownEndTime = 0;
        saveUsageState();
    }

    // 3. Check if cumulative time exceeded
    if (usageState.cumulativeTime >= FREE_LIMIT_MS) {
        usageState.cooldownEndTime = now + COOLDOWN_DURATION_MS;
        saveUsageState();
        return { allowed: false, reason: 'limit_reached', remainingMs: COOLDOWN_DURATION_MS };
    }

    const availableMs = FREE_LIMIT_MS - usageState.cumulativeTime;
    return { allowed: true, availableMs };
}

let fullscreenSessionStart = 0;
let fullscreenTimer = null;

function handleFullscreenExit(wasLimitReached = false) {
    if (!IS_FREE_VERSION) return;
    if (fullscreenTimer) {
        clearTimeout(fullscreenTimer);
        fullscreenTimer = null;
    }

    if (fullscreenSessionStart > 0) {
        const elapsed = Date.now() - fullscreenSessionStart;
        fullscreenSessionStart = 0;

        loadUsageState();
        usageState.cumulativeTime += elapsed;

        const now = Date.now();
        if (wasLimitReached || usageState.cumulativeTime >= FREE_LIMIT_MS) {
            usageState.cumulativeTime = FREE_LIMIT_MS;
            usageState.cooldownEndTime = now + COOLDOWN_DURATION_MS;
            saveUsageState();
            if (mainWindow && !mainWindow.isDestroyed()) {
                mainWindow.webContents.send('fullscreen-limit-reached', { remainingMs: COOLDOWN_DURATION_MS });
            }
        } else {
            saveUsageState();
        }
    }
}

process.on('uncaughtException', (err) => {
    try {
        fs.writeFileSync(getLogPath('crash.log'), 'Uncaught Exception:\n' + (err.stack || err.toString()));
    } catch (e) {}
});

process.on('unhandledRejection', (reason, promise) => {
    try {
        fs.writeFileSync(getLogPath('crash.log'), 'Unhandled Rejection:\n' + (reason.stack || reason.toString()));
    } catch (e) {}
});

let mainWindow = null;
let projectionWindow = null;
let miniWindow = null;
let normalBounds = null;
let isTransitioningFullscreen = false;
let capturedDisplayId = null;

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 1280,
        height: 720,
        minWidth: 900,
        minHeight: 600,
        minimizable: true, // Allow OS/programmatic minimization
        minimizeOnDeactivate: false, // Prevent minimizing when losing focus in fullscreen
        backgroundColor: '#030305',
        title: "FlipMyScreen // Ultimate Broadcast Monitor & Switcher",
        icon: path.join(__dirname, 'icon.png'),
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            contextIsolation: true,
            nodeIntegration: false,
            sandbox: false,
            backgroundThrottling: false
        }
    });

    mainWindow.loadFile('index.html');
    mainWindow.setMenuBarVisibility(false);

    mainWindow.webContents.once('did-finish-load', () => {
        updateWindowDisplayInfo();
    });

    normalBounds = mainWindow.getBounds();

    mainWindow.on('resized', () => {
        if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isMinimized() && !mainWindow.isMaximized() && !mainWindow.isFullScreen()) {
            normalBounds = mainWindow.getBounds();
        }
        updateWindowDisplayInfo();
    });

    mainWindow.on('moved', () => {
        if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isMinimized() && !mainWindow.isMaximized() && !mainWindow.isFullScreen()) {
            normalBounds = mainWindow.getBounds();
        }
        updateWindowDisplayInfo();
    });

    mainWindow.webContents.on('render-process-gone', (event, details) => {
        try {
            fs.appendFileSync(getLogPath('renderer.log'), `[main] Render process gone: ${JSON.stringify(details)}\n`);
        } catch (e) {}
    });

    mainWindow.on('closed', () => {
        try {
            fs.appendFileSync(getLogPath('renderer.log'), `[main] mainWindow closed\n`);
        } catch (e) {}
        if (projectionWindow) {
            projectionWindow.close();
        }
        if (miniWindow && !miniWindow.isDestroyed()) {
            miniWindow.close();
        }
        miniWindow = null;
        mainWindow = null;
    });

    mainWindow.on('restore', () => {
        exitMiniMode();
    });

    mainWindow.on('enter-html-full-screen', () => {
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.setAlwaysOnTop(true, 'screen-saver');
            mainWindow.webContents.send('fullscreen-change', true);
        }
    });
    mainWindow.on('leave-html-full-screen', () => {
        handleFullscreenExit(false);
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.setAlwaysOnTop(false);
            mainWindow.webContents.send('fullscreen-change', false);
            if (miniWindow && !miniWindow.isDestroyed()) {
                try {
                    miniWindow.close();
                } catch (e) {}
                miniWindow = null;
            }
        }
    });
    mainWindow.on('will-enter-full-screen', () => {
        isTransitioningFullscreen = true;
    });
    mainWindow.on('enter-full-screen', () => {
        try {
            fs.appendFileSync(getLogPath('renderer.log'), `[main] enter-full-screen event fired.\n`);
        } catch (e) {}
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.setAlwaysOnTop(true, 'screen-saver');
            mainWindow.webContents.send('fullscreen-change', true);
        }
        isTransitioningFullscreen = false;
    });
    mainWindow.on('will-leave-full-screen', () => {
        isTransitioningFullscreen = true;
    });
    mainWindow.on('leave-full-screen', () => {
        handleFullscreenExit(false);
        try {
            fs.appendFileSync(getLogPath('renderer.log'), `[main] leave-full-screen event fired.\n`);
        } catch (e) {}
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.setAlwaysOnTop(false);
            mainWindow.webContents.send('fullscreen-change', false);
            if (miniWindow && !miniWindow.isDestroyed()) {
                try {
                    miniWindow.close();
                } catch (e) {}
                miniWindow = null;
            }
        }
        isTransitioningFullscreen = false;
    });
}

// IPC Handlers
ipcMain.handle('get-sources', async () => {
    try {
        const sources = await desktopCapturer.getSources({
            types: ['window', 'screen'],
            thumbnailSize: { width: 0, height: 0 }
        });
        return sources.map(src => ({
            id: src.id,
            name: src.name,
            isScreen: src.id.startsWith('screen:')
        }));
    } catch (err) {
        console.error("Failed to query native desktop capturer sources:", err);
        return [];
    }
});

ipcMain.on('toggle-fullscreen', (event, displayId) => {
    if (!mainWindow || mainWindow.isDestroyed()) return;
    const isEnteringFs = !mainWindow.isFullScreen();
    
    if (isEnteringFs) {
        if (IS_FREE_VERSION) {
            const status = checkFullscreenAllowed();
            if (!status.allowed) {
                mainWindow.webContents.send('fullscreen-denied', {
                    reason: status.reason,
                    remainingMs: status.remainingMs
                });
                return;
            }

            fullscreenSessionStart = Date.now();
            if (usageState.windowStartTime === 0) {
                usageState.windowStartTime = fullscreenSessionStart;
            }
            saveUsageState();

            const availableMs = status.availableMs;
            if (fullscreenTimer) clearTimeout(fullscreenTimer);
            fullscreenTimer = setTimeout(() => {
                if (mainWindow && !mainWindow.isDestroyed() && mainWindow.isFullScreen()) {
                    mainWindow.setFullScreen(false);
                    handleFullscreenExit(true); // limit reached
                }
            }, availableMs);
        }

        // Save current bounds before fullscreen
        normalBounds = mainWindow.getBounds();
        
        if (displayId) {
            const targetDisplay = screen.getAllDisplays().find(d => String(d.id) === String(displayId));
            if (targetDisplay) {
                const { x, y } = targetDisplay.bounds;
                // Move window to the target display first, then enter fullscreen
                mainWindow.setBounds({ x, y, width: 1280, height: 720 });
                setTimeout(() => {
                    if (mainWindow && !mainWindow.isDestroyed()) {
                        mainWindow.setFullScreen(true);
                    }
                }, 50);
                return;
            }
        }
        mainWindow.setFullScreen(true);
    } else {
        mainWindow.setFullScreen(false);
        // Restore window back to its original display and bounds
        if (normalBounds) {
            setTimeout(() => {
                if (mainWindow && !mainWindow.isDestroyed()) {
                    mainWindow.setBounds(normalBounds);
                }
            }, 150);
        }
    }
});

ipcMain.handle('get-displays', () => {
    try {
        return screen.getAllDisplays().map(d => ({
            id: d.id,
            label: d.label || `Display ${d.id} (${d.bounds.width}x${d.bounds.height})`,
            bounds: d.bounds,
            isPrimary: d.id === screen.getPrimaryDisplay().id
        }));
    } catch (err) {
        console.error("Failed to retrieve displays:", err);
        return [];
    }
});

ipcMain.handle('activate-license', (event, key) => {
    if (validateLicenseKey(key)) {
        try {
            const licFile = getLogPath('license.key');
            fs.writeFileSync(licFile, key.trim().toUpperCase(), 'utf8');
            IS_FREE_VERSION = false;
            
            if (fullscreenTimer) {
                clearTimeout(fullscreenTimer);
                fullscreenTimer = null;
            }
            fullscreenSessionStart = 0;
            
            return { success: true, message: 'License key activated successfully! Pro version unlocked.' };
        } catch (e) {
            return { success: false, message: 'Failed to write license file: ' + e.message };
        }
    } else {
        return { success: false, message: 'Invalid license key format. Please check the code.' };
    }
});

ipcMain.handle('deactivate-license', () => {
    try {
        const licFile = getLogPath('license.key');
        if (fs.existsSync(licFile)) {
            fs.unlinkSync(licFile);
        }
        IS_FREE_VERSION = true;
        return { success: true, message: 'License deactivated. Reverted to Free Version.' };
    } catch (e) {
        return { success: false, message: 'Failed to delete license file: ' + e.message };
    }
});

ipcMain.handle('check-license-status', () => {
    const isLicensed = loadLicense();
    let activeKey = '';
    try {
        const licFile = getLogPath('license.key');
        if (fs.existsSync(licFile)) {
            activeKey = fs.readFileSync(licFile, 'utf8').trim();
        }
    } catch (e) {}
    
    return {
        isPro: !IS_FREE_VERSION,
        activeKey: activeKey
    };
});

ipcMain.on('start-projection', (event, { displayId, sourceId, transform }) => {
    try {
        fs.appendFileSync(getLogPath('renderer.log'), `[main] start-projection requested: displayId=${displayId}, sourceId=${sourceId}\n`);
    } catch (e) {}
    if (projectionWindow) {
        projectionWindow.close();
    }

    const targetDisplay = screen.getAllDisplays().find(d => String(d.id) === String(displayId)) || screen.getPrimaryDisplay();
    const { x, y, width, height } = targetDisplay.bounds;

    projectionWindow = new BrowserWindow({
        x, y, width, height,
        frame: false,
        fullscreen: false,
        alwaysOnTop: true,
        skipTaskbar: true,
        minimizable: false,
        minimizeOnDeactivate: false, // Prevent minimizing when losing focus in fullscreen
        backgroundColor: '#000000',
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            contextIsolation: true,
            nodeIntegration: false,
            sandbox: false,
            backgroundThrottling: false
        }
    });

    projectionWindow.setAlwaysOnTop(true, 'screen-saver');
    projectionWindow.setFullScreen(true);
    projectionWindow.show();
    projectionWindow.focus();

    const url = require('url');
    const fileUrl = url.pathToFileURL(path.join(__dirname, 'index.html'));
    fileUrl.searchParams.set('role', 'projection');
    fileUrl.searchParams.set('sourceId', sourceId);
    projectionWindow.loadURL(fileUrl.href);

    projectionWindow.webContents.once('did-finish-load', () => {
        projectionWindow.webContents.send('sync-transform', transform);
    });

    projectionWindow.on('closed', () => {
        try {
            fs.appendFileSync(getLogPath('renderer.log'), `[main] projectionWindow closed\n`);
        } catch (e) {}
        projectionWindow = null;
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.webContents.send('projection-closed');
        }
    });
});

ipcMain.on('stop-projection', () => {
    try {
        fs.appendFileSync(getLogPath('renderer.log'), `[main] stop-projection IPC received\n`);
    } catch (e) {}
    if (projectionWindow) {
        projectionWindow.close();
        projectionWindow = null;
    }
});

ipcMain.on('update-transform', (event, transform) => {
    if (projectionWindow && !projectionWindow.isDestroyed()) {
        projectionWindow.webContents.send('sync-transform', transform);
    }
});

ipcMain.on('open-external', (event, url) => {
    shell.openExternal(url);
});

// App lifecycle
app.whenReady().then(() => {
    loadLicense();
    session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
        callback(true);
    });
    session.defaultSession.setPermissionCheckHandler(() => true);

    try {
        const displays = screen.getAllDisplays();
        const primary = screen.getPrimaryDisplay();
        fs.writeFileSync(getLogPath('displays.log'), JSON.stringify({ displays, primary }, null, 2));
    } catch (e) {
        console.error("Failed to write displays log:", e);
    }

    app.on('web-contents-created', (event, contents) => {
        contents.on('console-message', (event, level, message, line, sourceId) => {
            try {
                fs.appendFileSync(getLogPath('renderer.log'), `[${contents.getType()}] ${message}\n`);
            } catch (e) {}
        });
    });

    createWindow();

    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
});

// Mini mode logic using a separate transparent frameless BrowserWindow
function enterMiniMode(displayId) {
    if (miniWindow && !miniWindow.isDestroyed()) return;
    if (!mainWindow || mainWindow.isDestroyed()) return;

    // Do NOT minimize the main window to taskbar so it continues to display the video feed (source monitor)

    // Calculate position for the mini-widget (bottom-left corner of the target screen, default to primary)
    let targetDisplay = null;
    if (displayId) {
        targetDisplay = screen.getAllDisplays().find(d => String(d.id) === String(displayId));
    }
    if (!targetDisplay) {
        targetDisplay = screen.getPrimaryDisplay();
    }

    const { x, y, width, height } = targetDisplay.bounds;
    const miniWidth = 90;
    const miniHeight = 54;
    const targetX = x + 20;
    const targetY = y + height - miniHeight - 40;

    miniWindow = new BrowserWindow({
        width: miniWidth,
        height: miniHeight,
        x: targetX,
        y: targetY,
        frame: false,
        resizable: false,
        maximizable: false,
        minimizable: false,
        alwaysOnTop: true,
        skipTaskbar: true,
        transparent: true,
        hasShadow: false, // Prevent Windows OS from applying a rectangular drop shadow to the transparent window
        backgroundColor: '#00000000', // transparent background
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            contextIsolation: true,
            nodeIntegration: false,
            sandbox: false,
            backgroundThrottling: false
        }
    });

    miniWindow.setAlwaysOnTop(true, 'screen-saver');

    const url = require('url');
    const fileUrl = url.pathToFileURL(path.join(__dirname, 'index.html'));
    fileUrl.searchParams.set('role', 'mini');
    miniWindow.loadURL(fileUrl.href);

    miniWindow.on('closed', () => {
        miniWindow = null;
    });
}

function exitMiniMode() {
    if (miniWindow && !miniWindow.isDestroyed()) {
        try {
            miniWindow.close();
        } catch (e) {}
        miniWindow = null;
    }
    if (mainWindow && !mainWindow.isDestroyed()) {
        if (mainWindow.isMinimized()) {
            mainWindow.restore();
        }
        mainWindow.focus();
        mainWindow.webContents.send('exit-mini-mode');
    }
}

// IPC listeners for mini widget mode
ipcMain.on('minimize-to-bar', (event, displayId) => {
    enterMiniMode(displayId);
});

ipcMain.on('restore-from-bar', () => {
    exitMiniMode();
});

ipcMain.on('set-captured-display', (event, displayId) => {
    capturedDisplayId = displayId;
});

ipcMain.on('move-mini-window', (event, { screenX, screenY }) => {
    if (miniWindow && !miniWindow.isDestroyed()) {
        miniWindow.setBounds({
            x: Math.round(screenX),
            y: Math.round(screenY),
            width: 90,
            height: 54
        });
    }
});

function updateWindowDisplayInfo() {
    if (!mainWindow || mainWindow.isDestroyed()) return;
    try {
        const winBounds = mainWindow.getBounds();
        const display = screen.getDisplayMatching(winBounds);
        const displays = screen.getAllDisplays();
        const displayIndex = displays.findIndex(d => d.id === display.id);
        const displayNum = displayIndex !== -1 ? displayIndex + 1 : 1;
        
        mainWindow.webContents.send('window-display-changed', {
            displayIndex: displayNum,
            label: display.label || `Display ${display.id}`
        });
    } catch (err) {
        console.error("Failed to update window display info:", err);
    }
}

