#!/usr/bin/env node
/**
 * ========================================
 *  ADMIN CLI INTERATIVO - API Keys
 * ========================================
 */

const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const readline = require('readline');
const Database = require('better-sqlite3');

// Mesma config do api.js
const DB_FOLDER_NAME = 'f7imr6zs30ovzazu';
const DB_DIR = path.join(__dirname, DB_FOLDER_NAME);
const DB_PATH = path.join(DB_DIR, 'keys.db');

// Cores
const C = {
    reset: '\x1b[0m',
    bright: '\x1b[1m',
    dim: '\x1b[2m',
    red: '\x1b[31m',
    green: '\x1b[32m',
    yellow: '\x1b[33m',
    blue: '\x1b[34m',
    magenta: '\x1b[35m',
    cyan: '\x1b[36m',
    gray: '\x1b[90m',
    bgBlue: '\x1b[44m',
    bgGreen: '\x1b[42m',
    bgRed: '\x1b[41m',
    white: '\x1b[37m',
};

// ========== DATABASE ==========

function getDB() {
    if (!fs.existsSync(DB_DIR)) {
        fs.mkdirSync(DB_DIR, { recursive: true });
    }
    const db = new Database(DB_PATH);
    db.pragma('journal_mode = WAL');

    db.exec(`CREATE TABLE IF NOT EXISTS api_keys (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        key_value TEXT UNIQUE NOT NULL,
        owner TEXT DEFAULT '',
        created_at TEXT DEFAULT (datetime('now', 'localtime')),
        expires_at TEXT NOT NULL,
        active INTEGER DEFAULT 1,
        total_requests INTEGER DEFAULT 0,
        last_used_at TEXT
    )`);

    db.exec(`CREATE TABLE IF NOT EXISTS request_log (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        key_value TEXT NOT NULL,
        placa TEXT NOT NULL,
        timestamp TEXT DEFAULT (datetime('now', 'localtime')),
        success INTEGER DEFAULT 0,
        ip TEXT DEFAULT ''
    )`);

    return db;
}

function generateKey() {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let key = '';
    const bytes = crypto.randomBytes(32);
    for (let i = 0; i < 32; i++) {
        key += chars[bytes[i] % chars.length];
    }
    return key;
}

function statusLabel(active, expiresAt) {
    const now = new Date();
    const exp = new Date(expiresAt);
    if (!active) return `${C.red}● DESATIVADA${C.reset}`;
    if (exp < now) return `${C.yellow}● EXPIRADA${C.reset}`;
    const diffDays = Math.ceil((exp - now) / 86400000);
    if (diffDays <= 7) return `${C.yellow}● ATIVA (${diffDays}d restantes)${C.reset}`;
    return `${C.green}● ATIVA (${diffDays}d restantes)${C.reset}`;
}

// ========== I/O ==========

const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

function ask(question) {
    return new Promise(resolve => rl.question(question, a => resolve(a.trim())));
}

function clear() {
    process.stdout.write('\x1b[2J\x1b[H');
}

function line(len = 60) {
    return `${C.gray}${'─'.repeat(len)}${C.reset}`;
}

function header(title) {
    clear();
    console.log('');
    console.log(`  ${C.bgBlue}${C.white}${C.bright}  ${title}  ${C.reset}`);
    console.log(line());
}

function pause() {
    return ask(`\n  ${C.gray}Enter para voltar...${C.reset}`);
}

// ========== MENU INTERATIVO COM SETAS ==========

function selectMenu(title, options) {
    return new Promise(resolve => {
        let selected = 0;
        const selectable = options.map((o, i) => o.separator ? -1 : i).filter(i => i >= 0);
        if (!selectable.includes(selected)) selected = selectable[0] || 0;

        function render() {
            clear();
            console.log('');
            console.log(`  ${C.bgBlue}${C.white}${C.bright}  ${title}  ${C.reset}`);
            console.log(line());
            console.log('');

            options.forEach((opt, i) => {
                if (opt.separator) {
                    console.log(`  ${C.gray}${opt.label || ''}${C.reset}`);
                    return;
                }
                if (i === selected) {
                    console.log(`  ${C.cyan}${C.bright} ❯ ${opt.label}${C.reset}`);
                } else {
                    console.log(`    ${C.dim}${opt.label}${C.reset}`);
                }
            });

            console.log('');
            console.log(`  ${C.gray}↑↓ navegar  │  Enter selecionar  │  q sair${C.reset}`);
        }

        render();

        if (process.stdin.isTTY) process.stdin.setRawMode(true);
        process.stdin.resume();

        function onKey(buf) {
            const k = buf.toString();

            if (k === 'q' || k === '\x03') { cleanup(); resolve(null); return; }
            if (k === '\r' || k === '\n') { cleanup(); resolve(options[selected]?.value ?? null); return; }

            if (k === '\x1b[A') { // up
                const ci = selectable.indexOf(selected);
                selected = ci > 0 ? selectable[ci - 1] : selectable[selectable.length - 1];
                render();
            }
            if (k === '\x1b[B') { // down
                const ci = selectable.indexOf(selected);
                selected = ci < selectable.length - 1 ? selectable[ci + 1] : selectable[0];
                render();
            }

            // Número direto
            const num = parseInt(k);
            if (num >= 0 && num <= 9) {
                const idx = num === 0 ? selectable.length - 1 : num - 1;
                if (idx >= 0 && idx < selectable.length) {
                    selected = selectable[idx];
                    cleanup();
                    resolve(options[selected]?.value ?? null);
                }
            }
        }

        function cleanup() {
            process.stdin.removeListener('data', onKey);
            if (process.stdin.isTTY) process.stdin.setRawMode(false);
        }

        process.stdin.on('data', onKey);
    });
}

// Selecionar key da lista
async function selectKey(title) {
    const db = getDB();
    const keys = db.prepare('SELECT * FROM api_keys ORDER BY id ASC').all();
    db.close();

    if (keys.length === 0) {
        header(title);
        console.log(`\n  ${C.yellow}Nenhuma key cadastrada.${C.reset}`);
        await pause();
        return null;
    }

    const options = keys.map(k => {
        const st = k.active
            ? (new Date(k.expires_at) < new Date() ? `${C.yellow}EXP${C.reset}` : `${C.green}OK ${C.reset}`)
            : `${C.red}OFF${C.reset}`;
        return {
            label: `[${st}] ${k.key_value.slice(0, 16)}...  ${C.gray}owner: ${k.owner || '—'}  reqs: ${k.total_requests}${C.reset}`,
            value: k.key_value,
        };
    });
    options.push({ label: `${C.gray}← Voltar${C.reset}`, value: '__back__' });

    const choice = await selectMenu(title, options);
    return (choice === '__back__' || choice === null) ? null : choice;
}

// ========== AÇÕES ==========

async function actionList() {
    const db = getDB();
    const keys = db.prepare('SELECT * FROM api_keys ORDER BY id ASC').all();
    db.close();

    header('TODAS AS KEYS');
    console.log('');

    if (keys.length === 0) {
        console.log(`  ${C.yellow}Nenhuma key cadastrada.${C.reset}`);
        await pause();
        return;
    }

    for (const k of keys) {
        console.log(`  ${C.bright}#${k.id}${C.reset}  ${statusLabel(k.active, k.expires_at)}`);
        console.log(`  ${C.cyan}Key:${C.reset}     ${C.bright}${k.key_value}${C.reset}`);
        console.log(`  ${C.cyan}Owner:${C.reset}   ${k.owner || '—'}`);
        console.log(`  ${C.cyan}Expira:${C.reset}  ${k.expires_at}`);
        console.log(`  ${C.cyan}Reqs:${C.reset}    ${k.total_requests}  ${C.gray}último: ${k.last_used_at || 'nunca'}${C.reset}`);
        console.log(line(50));
    }
    console.log(`\n  ${C.gray}Total: ${keys.length} key(s)${C.reset}`);
    await pause();
}

async function actionCreate() {
    header('CRIAR NOVA KEY');
    console.log('');

    const owner = await ask(`  ${C.cyan}Nome do cliente (owner):${C.reset} `);
    if (!owner) { console.log(`  ${C.red}Cancelado.${C.reset}`); await pause(); return; }

    const diasStr = await ask(`  ${C.cyan}Dias de validade:${C.reset} `);
    const dias = parseInt(diasStr);
    if (isNaN(dias) || dias < 1) { console.log(`  ${C.red}Número inválido.${C.reset}`); await pause(); return; }

    const key = generateKey();
    const exp = new Date(Date.now() + dias * 86400000).toISOString().replace('T', ' ').slice(0, 19);

    const db = getDB();
    db.prepare('INSERT INTO api_keys (key_value, owner, expires_at) VALUES (?, ?, ?)').run(key, owner, exp);
    db.close();

    console.log('');
    console.log(`  ${C.bgGreen}${C.white}${C.bright}  ✓ KEY CRIADA  ${C.reset}`);
    console.log(`  ${C.cyan}Key:${C.reset}     ${C.bright}${key}${C.reset}`);
    console.log(`  ${C.cyan}Owner:${C.reset}   ${owner}`);
    console.log(`  ${C.cyan}Expira:${C.reset}  ${exp}  (${dias} dias)`);
    await pause();
}

async function actionAdd() {
    header('ADICIONAR KEY MANUAL');
    console.log('');

    const key = await ask(`  ${C.cyan}Key:${C.reset} `);
    if (!key) { console.log(`  ${C.red}Cancelado.${C.reset}`); await pause(); return; }

    const owner = await ask(`  ${C.cyan}Owner:${C.reset} `);
    if (!owner) { console.log(`  ${C.red}Cancelado.${C.reset}`); await pause(); return; }

    const exp = await ask(`  ${C.cyan}Expira (YYYY-MM-DD HH:MM:SS):${C.reset} `);
    if (!exp) { console.log(`  ${C.red}Cancelado.${C.reset}`); await pause(); return; }

    const db = getDB();
    if (db.prepare('SELECT id FROM api_keys WHERE key_value = ?').get(key)) {
        console.log(`  ${C.red}Erro: Key já existe!${C.reset}`);
        db.close(); await pause(); return;
    }

    db.prepare('INSERT INTO api_keys (key_value, owner, expires_at) VALUES (?, ?, ?)').run(key, owner, exp);
    db.close();

    console.log('');
    console.log(`  ${C.bgGreen}${C.white}${C.bright}  ✓ KEY ADICIONADA  ${C.reset}`);
    console.log(`  ${C.cyan}Key:${C.reset}     ${C.bright}${key}${C.reset}`);
    console.log(`  ${C.cyan}Owner:${C.reset}   ${owner}`);
    console.log(`  ${C.cyan}Expira:${C.reset}  ${exp}`);
    await pause();
}

async function actionRemove() {
    const keyValue = await selectKey('REMOVER KEY');
    if (!keyValue) return;

    header('CONFIRMAR REMOÇÃO');
    console.log('');
    console.log(`  ${C.red}${C.bright}Vai deletar: ${keyValue}${C.reset}`);
    console.log('');

    const confirm = await ask(`  ${C.red}Digita SIM para confirmar:${C.reset} `);
    if (confirm !== 'SIM') { console.log(`  ${C.yellow}Cancelado.${C.reset}`); await pause(); return; }

    const db = getDB();
    db.prepare('DELETE FROM request_log WHERE key_value = ?').run(keyValue);
    db.prepare('DELETE FROM api_keys WHERE key_value = ?').run(keyValue);
    db.close();

    console.log(`\n  ${C.bgRed}${C.white}${C.bright}  ✓ KEY REMOVIDA  ${C.reset}`);
    await pause();
}

async function actionExtend() {
    const keyValue = await selectKey('ESTENDER KEY');
    if (!keyValue) return;

    const db = getDB();
    const k = db.prepare('SELECT * FROM api_keys WHERE key_value = ?').get(keyValue);

    header('ESTENDER EXPIRAÇÃO');
    console.log('');
    console.log(`  ${C.cyan}Key:${C.reset}     ${k.key_value}`);
    console.log(`  ${C.cyan}Owner:${C.reset}   ${k.owner}`);
    console.log(`  ${C.cyan}Expira:${C.reset}  ${k.expires_at}`);
    console.log('');

    const diasStr = await ask(`  ${C.cyan}Quantos dias adicionar:${C.reset} `);
    const dias = parseInt(diasStr);
    if (isNaN(dias) || dias < 1) { console.log(`  ${C.red}Inválido.${C.reset}`); db.close(); await pause(); return; }

    const base = new Date(k.expires_at) > new Date() ? new Date(k.expires_at) : new Date();
    const newExp = new Date(base.getTime() + dias * 86400000).toISOString().replace('T', ' ').slice(0, 19);

    db.prepare('UPDATE api_keys SET expires_at = ?, active = 1 WHERE key_value = ?').run(newExp, keyValue);
    db.close();

    console.log('');
    console.log(`  ${C.bgGreen}${C.white}${C.bright}  ✓ ESTENDIDA  ${C.reset}`);
    console.log(`  ${C.cyan}Antes:${C.reset}  ${k.expires_at}`);
    console.log(`  ${C.cyan}Agora:${C.reset}  ${C.bright}${newExp}${C.reset}  (+${dias} dias)`);
    await pause();
}

async function actionToggle() {
    const keyValue = await selectKey('ATIVAR / DESATIVAR');
    if (!keyValue) return;

    const db = getDB();
    const k = db.prepare('SELECT * FROM api_keys WHERE key_value = ?').get(keyValue);
    const newActive = k.active ? 0 : 1;
    db.prepare('UPDATE api_keys SET active = ? WHERE key_value = ?').run(newActive, keyValue);
    db.close();

    header('TOGGLE');
    console.log('');
    if (newActive) {
        console.log(`  ${C.bgGreen}${C.white}${C.bright}  ✓ KEY ATIVADA  ${C.reset}`);
    } else {
        console.log(`  ${C.bgRed}${C.white}${C.bright}  ✓ KEY DESATIVADA  ${C.reset}`);
    }
    console.log(`  ${C.cyan}Key:${C.reset} ${keyValue}`);
    await pause();
}

async function actionInfo() {
    const keyValue = await selectKey('INFO DETALHADA');
    if (!keyValue) return;

    const db = getDB();
    const k = db.prepare('SELECT * FROM api_keys WHERE key_value = ?').get(keyValue);
    const logCount = db.prepare('SELECT COUNT(*) as cnt FROM request_log WHERE key_value = ?').get(keyValue);
    const lastReqs = db.prepare('SELECT * FROM request_log WHERE key_value = ? ORDER BY id DESC LIMIT 10').all(keyValue);
    db.close();

    header('DETALHES DA KEY');
    console.log('');
    console.log(`  ${C.cyan}ID:${C.reset}          ${k.id}`);
    console.log(`  ${C.cyan}Key:${C.reset}         ${C.bright}${k.key_value}${C.reset}`);
    console.log(`  ${C.cyan}Owner:${C.reset}       ${k.owner || '—'}`);
    console.log(`  ${C.cyan}Status:${C.reset}      ${statusLabel(k.active, k.expires_at)}`);
    console.log(`  ${C.cyan}Criada:${C.reset}      ${k.created_at || '—'}`);
    console.log(`  ${C.cyan}Expira:${C.reset}      ${k.expires_at}`);
    console.log(`  ${C.cyan}Total Reqs:${C.reset}  ${k.total_requests}`);
    console.log(`  ${C.cyan}Logs no DB:${C.reset}  ${logCount.cnt}`);
    console.log(`  ${C.cyan}Último uso:${C.reset}  ${k.last_used_at || 'nunca'}`);

    if (lastReqs.length > 0) {
        console.log('');
        console.log(`  ${C.bright}Últimos requests:${C.reset}`);
        console.log(`  ${line(50)}`);
        for (const r of lastReqs) {
            const ok = r.success ? `${C.green}OK${C.reset}  ` : `${C.red}FAIL${C.reset}`;
            console.log(`  ${C.gray}${r.timestamp}${C.reset}  ${r.placa.padEnd(10)} ${ok}  ${C.gray}${r.ip || '—'}${C.reset}`);
        }
    }
    await pause();
}

async function actionLogs() {
    const keyValue = await selectKey('VER LOGS');
    if (!keyValue) return;

    header(`LOGS: ${keyValue.slice(0, 16)}...`);
    console.log('');

    const db = getDB();
    const logs = db.prepare('SELECT * FROM request_log WHERE key_value = ? ORDER BY id DESC LIMIT 50').all(keyValue);
    db.close();

    if (logs.length === 0) {
        console.log(`  ${C.yellow}Nenhum log para essa key.${C.reset}`);
        await pause();
        return;
    }

    console.log(`  ${'TIMESTAMP'.padEnd(22)} ${'PLACA'.padEnd(10)} ${'STATUS'.padEnd(6)} IP`);
    console.log(`  ${line(55)}`);
    for (const r of logs) {
        const ok = r.success ? `${C.green}OK${C.reset}  ` : `${C.red}FAIL${C.reset}`;
        console.log(`  ${C.gray}${r.timestamp}${C.reset}  ${r.placa.padEnd(10)} ${ok}  ${C.gray}${r.ip || '—'}${C.reset}`);
    }
    console.log(`\n  ${C.gray}Últimos ${logs.length} registros${C.reset}`);
    await pause();
}

// ========== MENU PRINCIPAL ==========

async function main() {
    while (true) {
        const choice = await selectMenu('ADMIN — API Keys Manager', [
            { label: `1  📋  Listar keys`, value: 'list' },
            { label: `2  🔑  Criar nova key`, value: 'create' },
            { label: `3  ➕  Adicionar key manual`, value: 'add' },
            { label: `4  🗑️   Remover key`, value: 'remove' },
            { label: `5  ⏳  Estender expiração`, value: 'extend' },
            { label: `6  🔄  Ativar / Desativar`, value: 'toggle' },
            { label: `7  🔍  Info detalhada`, value: 'info' },
            { label: `8  📊  Ver logs de uso`, value: 'logs' },
            { separator: true, label: '' },
            { label: `0  ❌  Sair`, value: 'exit' },
        ]);

        if (choice === 'exit' || choice === null) {
            clear();
            console.log(`\n  ${C.gray}Bye!${C.reset}\n`);
            rl.close();
            process.exit(0);
        }

        switch (choice) {
            case 'list':   await actionList(); break;
            case 'create': await actionCreate(); break;
            case 'add':    await actionAdd(); break;
            case 'remove': await actionRemove(); break;
            case 'extend': await actionExtend(); break;
            case 'toggle': await actionToggle(); break;
            case 'info':   await actionInfo(); break;
            case 'logs':   await actionLogs(); break;
        }
    }
}

main().catch(err => {
    console.error(`${C.red}Erro:${C.reset}`, err);
    process.exit(1);
});
