import 'dotenv/config';
import { v2 as webdav } from 'webdav-server';
import { db } from '../../db';
import { tenants, files, folders } from '../../db/schema';
import { Readable } from 'stream';
import { GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
import { s3, initS3 } from '../utils/s3';
import { secrets, loadSecrets } from '../utils/secrets';

// ============================================================================
// 1. SETUP
// ============================================================================

const userManager = new webdav.SimpleUserManager();
const user = userManager.addUser('admin', 'admin', true);

const privilegeManager = new webdav.SimplePathPrivilegeManager();
privilegeManager.setRights(user, '/', [ 'all' ]);

const server = new webdav.WebDAVServer({
    httpAuthentication: new webdav.HTTPDigestAuthentication(userManager, 'Default realm'),
    privilegeManager: privilegeManager,
    port: 3200,
    headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS,PROPFIND,PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK',
        'Access-Control-Allow-Headers': 'Authorization, Content-Type, Depth, User-Agent, X-Expected-Entity-Length, If-Modified-Since, Cache-Control, Range, Overwrite, Destination',
    }
});

// ============================================================================
// 2. CACHE
// ============================================================================

const pathToS3KeyMap = new Map<string, string>();
const pathToSizeMap = new Map<string, number>();

// ============================================================================
// 3. LOGIC
// ============================================================================

async function startServer() {
    console.log('------------------------------------------------');
    console.log('[WebDAV] Starte Server (Filtered Mode)...');

    try {
        await loadSecrets();
        await initS3();
        console.log('[WebDAV] S3 Verbindung OK.');

        console.log('[WebDAV] Lade Datenbank...');
        const allTenants = await db.select().from(tenants);
        const allFolders = await db.select().from(folders);
        const allFiles = await db.select().from(files);

        // Zähler für Statistik
        let hiddenFilesCount = 0;

        // --------------------------------------------------------------------
        // BUILDER
        // --------------------------------------------------------------------
        const buildFolderContent = (tenantId: string, parentFolderId: string | null, currentWebDavPath: string) => {
            const currentDir: any = {};

            // 1. UNTERORDNER
            const subFolders = allFolders.filter(f => f.tenant === tenantId && f.parent === parentFolderId);
            subFolders.forEach(folder => {
                const folderName = folder.name.replace(/\//g, '-');
                const nextPath = `${currentWebDavPath}/${folderName}`;
                currentDir[folderName] = buildFolderContent(tenantId, folder.id, nextPath);
            });

            // 2. DATEIEN
            //@ts-ignore
            const dirFiles = allFiles.filter(f => f.tenant === tenantId && f.folder === parentFolderId);

            dirFiles.forEach(file => {
                // ============================================================
                // ❌ FILTER: DATEIEN OHNE GRÖSSE AUSBLENDEN
                // ============================================================
                const fileSize = Number(file.size || 0);

                if (fileSize <= 0) {
                    // Datei überspringen, wenn 0 Bytes oder null
                    hiddenFilesCount++;
                    return;
                }
                // ============================================================

                // Name bestimmen
                let fileName = 'Unbenannt';
                if (file.path) fileName = file.path.split('/').pop() || 'Unbenannt';
                else if (file.name) fileName = file.name;

                // A) Eintrag im WebDAV
                currentDir[fileName] = `Ref: ${file.id}`;

                // B) Maps füllen
                const webDavFullPath = `${currentWebDavPath}/${fileName}`;

                if (file.path) {
                    pathToS3KeyMap.set(webDavFullPath, file.path);
                }

                // C) Größe setzen (wir wissen jetzt sicher, dass sie > 0 ist)
                pathToSizeMap.set(webDavFullPath, fileSize);
            });

            return currentDir;
        };

        // --------------------------------------------------------------------
        // BAUM ZUSAMMENSETZEN
        // --------------------------------------------------------------------
        const dbTree: any = {};

        allTenants.forEach(tenant => {
            const tName = tenant.name.replace(/\//g, '-');
            const rootPath = `/${tName}`;
            //@ts-ignore
            const content = buildFolderContent(tenant.id, null, rootPath);

            // Leere Ordner Hinweis (optional)
            if (Object.keys(content).length === 0) {
                content['(Leer).txt'] = 'Keine gültigen Dateien vorhanden.';
            }
            dbTree[tName] = content;
        });

        if (Object.keys(dbTree).length === 0) {
            dbTree['Status.txt'] = 'Datenbank leer.';
        }

        // --------------------------------------------------------------------
        // REGISTRIEREN
        // --------------------------------------------------------------------
        const rootFS = server.rootFileSystem();
        //@ts-ignore
        rootFS.addSubTree(server.createExternalContext(), dbTree);

        // ====================================================================
        // OVERRIDE 1: DOWNLOAD
        // ====================================================================
        (rootFS as any)._openReadStream = async (path: webdav.Path, ctx: any, callback: any) => {
            const p = path.toString();
            const s3Key = pathToS3KeyMap.get(p);

            if (s3Key) {
                try {
                    const command = new GetObjectCommand({ Bucket: secrets.S3_BUCKET, Key: s3Key });
                    const response = await s3.send(command);
                    if (response.Body) return callback(null, response.Body as Readable);
                } catch (e: any) {
                    console.error(`[S3 ERROR] ${e.message}`);
                    return callback(null, Readable.from([`Error: ${e.message}`]));
                }
            }
            return callback(null, Readable.from(['System File']));
        };

        // ====================================================================
        // OVERRIDE 2: SIZE
        // ====================================================================
        (rootFS as any)._size = async (path: webdav.Path, ctx: any, callback: any) => {
            const p = path.toString();
            const cachedSize = pathToSizeMap.get(p);

            if (cachedSize !== undefined) return callback(null, cachedSize);

            // Fallback S3 Check (sollte durch Filter kaum noch vorkommen)
            const s3Key = pathToS3KeyMap.get(p);
            if (s3Key) {
                try {
                    const command = new HeadObjectCommand({ Bucket: secrets.S3_BUCKET, Key: s3Key });
                    const response = await s3.send(command);
                    const realSize = response.ContentLength || 0;
                    pathToSizeMap.set(p, realSize);
                    return callback(null, realSize);
                } catch (e) {
                    return callback(null, 0);
                }
            }
            return callback(null, 0);
        };

        // --------------------------------------------------------------------
        // START
        // --------------------------------------------------------------------
        server.start(() => {
            console.log('[WebDAV] 🚀 READY auf http://localhost:3200');
            console.log(`[WebDAV] Sichtbare Dateien: ${pathToS3KeyMap.size}`);
            console.log(`[WebDAV] Ausgeblendet (0 Bytes): ${hiddenFilesCount}`);
        });

    } catch (error) {
        console.error('[WebDAV] 💥 ERROR:', error);
    }
}

startServer();