const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const { getDatabase } = require('../config/database');

const UPLOAD_DIR = path.join(__dirname, '../../uploads/shares');
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });

// multer konfiguriert in routes
const multer = require('multer');
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, UPLOAD_DIR),
    filename: (req, file, cb) => {
        const ext = path.extname(file.originalname);
        cb(null, crypto.randomBytes(16).toString('hex') + ext);
    },
});
const upload = multer({ storage, limits: { fileSize: 100 * 1024 * 1024 } }); // 100 MB

// ── Admin: Share erstellen ────────────────────────────────────────────────────
const createShare = [
    upload.single('file'),
    async (req, res) => {
        try {
            const { type, text_content, password, expires_in_hours, max_downloads } = req.body;
            if (!type || !['file', 'text'].includes(type)) {
                return res.status(400).json({ error: 'type muss "file" oder "text" sein' });
            }
            if (type === 'text' && !text_content?.trim()) {
                return res.status(400).json({ error: 'text_content erforderlich' });
            }
            if (type === 'file' && !req.file) {
                return res.status(400).json({ error: 'Datei erforderlich' });
            }

            const token = crypto.randomBytes(24).toString('base64url');
            const password_hash = password ? await bcrypt.hash(password, 10) : null;
            const expires_at = expires_in_hours
                ? new Date(Date.now() + parseInt(expires_in_hours) * 3600 * 1000).toISOString().replace('T', ' ').slice(0, 19)
                : null;

            const db = getDatabase();
            const result = db.prepare(`
                INSERT INTO shares (token, type, filename, stored_filename, text_content,
                    password_hash, expires_at, max_downloads, created_by_user_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            `).run(
                token, type,
                req.file?.originalname || null,
                req.file?.filename || null,
                type === 'text' ? text_content.trim() : null,
                password_hash,
                expires_at,
                max_downloads ? parseInt(max_downloads) : null,
                req.user.id
            );

            const share = db.prepare('SELECT * FROM shares WHERE id = ?').get(result.lastInsertRowid);
            const publicUrl = `${process.env.FRONTEND_URL || ''}/s/${token}`;
            res.status(201).json({ ...share, public_url: publicUrl });
        } catch (e) {
            console.error('[Share] createShare error:', e.message);
            res.status(500).json({ error: 'Interner Fehler' });
        }
    }
];

// ── Admin: Alle Shares ────────────────────────────────────────────────────────
const getAllShares = (req, res) => {
    const db = getDatabase();
    const rows = db.prepare(`
        SELECT s.*, u.username as created_by_username
        FROM shares s
        LEFT JOIN users u ON s.created_by_user_id = u.id
        WHERE s.deleted_at IS NULL
        ORDER BY s.created_at DESC
    `).all();
    const base = process.env.FRONTEND_URL || '';
    res.json(rows.map(r => ({ ...r, public_url: `${base}/s/${r.token}` })));
};

// ── Admin: Share löschen ──────────────────────────────────────────────────────
const deleteShare = (req, res) => {
    const db = getDatabase();
    const share = db.prepare('SELECT * FROM shares WHERE id = ? AND deleted_at IS NULL').get(req.params.id);
    if (!share) return res.status(404).json({ error: 'Nicht gefunden' });

    if (share.stored_filename) {
        const filePath = path.join(UPLOAD_DIR, share.stored_filename);
        if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
    }

    db.prepare("UPDATE shares SET deleted_at = datetime('now') WHERE id = ?").run(req.params.id);
    res.json({ success: true });
};

// ── Public: Share-Info (kein Auth) ───────────────────────────────────────────
const getPublicShare = (req, res) => {
    const db = getDatabase();
    const share = db.prepare(`
        SELECT id, token, type, filename, text_content, expires_at, max_downloads,
               download_count, created_at, password_hash IS NOT NULL as has_password
        FROM shares
        WHERE token = ? AND deleted_at IS NULL
    `).get(req.params.token);

    if (!share) return res.status(404).json({ error: 'Link nicht gefunden oder abgelaufen' });

    if (share.expires_at && new Date(share.expires_at + 'Z') < new Date()) {
        return res.status(410).json({ error: 'Dieser Link ist abgelaufen' });
    }
    if (share.max_downloads && share.download_count >= share.max_downloads) {
        return res.status(410).json({ error: 'Maximale Anzahl Downloads erreicht' });
    }

    res.json({
        id: share.id,
        token: share.token,
        type: share.type,
        filename: share.filename,
        expires_at: share.expires_at,
        max_downloads: share.max_downloads,
        download_count: share.download_count,
        has_password: !!share.has_password,
        // Text nur senden wenn kein Passwort gesetzt
        text_content: share.has_password ? null : share.text_content,
    });
};

// ── Public: Passwort prüfen + Text freischalten ───────────────────────────────
const accessShare = async (req, res) => {
    const { password } = req.body;
    const db = getDatabase();
    const share = db.prepare(`
        SELECT * FROM shares WHERE token = ? AND deleted_at IS NULL
    `).get(req.params.token);

    if (!share) return res.status(404).json({ error: 'Nicht gefunden' });
    if (share.expires_at && new Date(share.expires_at + 'Z') < new Date()) {
        return res.status(410).json({ error: 'Abgelaufen' });
    }

    if (share.password_hash) {
        if (!password) return res.status(401).json({ error: 'Passwort erforderlich' });
        const ok = await bcrypt.compare(password, share.password_hash);
        if (!ok) return res.status(401).json({ error: 'Falsches Passwort' });
    }

    if (share.type === 'text') {
        res.json({ text_content: share.text_content });
    } else {
        res.json({ ready: true });
    }
};

// ── Public: Datei-Download ────────────────────────────────────────────────────
const downloadFile = async (req, res) => {
    const { password } = req.query;
    const db = getDatabase();
    const share = db.prepare('SELECT * FROM shares WHERE token = ? AND deleted_at IS NULL').get(req.params.token);

    if (!share || share.type !== 'file') return res.status(404).json({ error: 'Nicht gefunden' });
    if (share.expires_at && new Date(share.expires_at + 'Z') < new Date()) {
        return res.status(410).json({ error: 'Abgelaufen' });
    }
    if (share.max_downloads && share.download_count >= share.max_downloads) {
        return res.status(410).json({ error: 'Download-Limit erreicht' });
    }

    if (share.password_hash) {
        if (!password) return res.status(401).json({ error: 'Passwort erforderlich' });
        const ok = await bcrypt.compare(password, share.password_hash);
        if (!ok) return res.status(401).json({ error: 'Falsches Passwort' });
    }

    const filePath = path.join(UPLOAD_DIR, share.stored_filename);
    if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'Datei nicht vorhanden' });

    db.prepare('UPDATE shares SET download_count = download_count + 1 WHERE id = ?').run(share.id);
    res.download(filePath, share.filename);
};

// ── Cleanup-Cron: abgelaufene/verbrauchte Shares löschen ────────────────────
const cleanupExpired = () => {
    try {
        const db = getDatabase();
        const expired = db.prepare(`
            SELECT * FROM shares
            WHERE deleted_at IS NULL AND (
                (expires_at IS NOT NULL AND expires_at < datetime('now'))
                OR (max_downloads IS NOT NULL AND download_count >= max_downloads)
            )
        `).all();

        for (const share of expired) {
            if (share.stored_filename) {
                const filePath = path.join(UPLOAD_DIR, share.stored_filename);
                if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
            }
            db.prepare("UPDATE shares SET deleted_at = datetime('now') WHERE id = ?").run(share.id);
        }
        if (expired.length > 0) console.log(`[Shares] ${expired.length} abgelaufene Share(s) bereinigt`);
    } catch (e) {
        console.error('[Shares] Cleanup-Fehler:', e.message);
    }
};

module.exports = { createShare, getAllShares, deleteShare, getPublicShare, accessShare, downloadFile, cleanupExpired };
