/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { createReadStream, readFileSync, statSync } from 'node:fs';
import { Readable } from 'node:stream';
import { Hono } from 'hono';
import { getWorkspaceCwd } from '../middleware/workspace.js';
import { addEntry, DEFAULT_ALLOWED_FOLDERS, getEntryFile, initVault, readManifest, removeEntry, updateEntry, validateMime, } from '../../services/context-vault.js';
export function contextRoute(cwd) {
    const app = new Hono();
    // GET / — List manifest entries with optional folder/tag filtering
    app.get('/', (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const manifest = readManifest(dir);
        const folderFilter = c.req.query('folder');
        const tagFilter = c.req.query('tag');
        let entries = manifest.entries;
        if (folderFilter) {
            entries = entries.filter((e) => e.folder === folderFilter);
        }
        if (tagFilter) {
            entries = entries.filter((e) => e.tags.includes(tagFilter));
        }
        return c.json({ entries, total: entries.length });
    });
    // POST /upload — Multipart upload with file + metadata
    app.post('/upload', async (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        // Ensure vault is initialized
        initVault(dir);
        const body = await c.req.parseBody();
        const file = body['file'];
        const metadata = body['metadata'];
        if (!file || !(file instanceof File)) {
            return c.json({ error: 'Missing file in multipart body' }, 400);
        }
        // Parse metadata JSON
        let meta = {};
        if (metadata && typeof metadata === 'string') {
            try {
                meta = JSON.parse(metadata);
            }
            catch {
                return c.json({ error: 'Invalid metadata JSON' }, 400);
            }
        }
        const folder = meta.folder ?? 'docs';
        const mimeType = file.type || 'application/octet-stream';
        // Validate MIME type
        if (!validateMime(mimeType)) {
            return c.json({ error: `Unsupported media type: ${mimeType}` }, 415);
        }
        // Validate folder
        if (!DEFAULT_ALLOWED_FOLDERS.includes(folder)) {
            return c.json({ error: `Invalid folder: ${folder}. Allowed: ${DEFAULT_ALLOWED_FOLDERS.join(', ')}` }, 400);
        }
        // Read file data
        const arrayBuffer = await file.arrayBuffer();
        const data = Buffer.from(arrayBuffer);
        // Check size
        const manifest = readManifest(dir);
        const maxBytes = manifest.maxFileSizeMb * 1024 * 1024;
        if (data.length > maxBytes) {
            return c.json({ error: `File exceeds maximum size of ${manifest.maxFileSizeMb}MB` }, 413);
        }
        try {
            const entry = await addEntry(dir, {
                filename: file.name,
                folder,
                mimeType,
                tags: meta.tags,
                description: meta.description,
                data,
            });
            return c.json({ entry }, 201);
        }
        catch (err) {
            const message = err instanceof Error ? err.message : 'Upload failed';
            return c.json({ error: message }, 500);
        }
    });
    // POST /folder — Create a new folder (validates against allowed names)
    app.post('/folder', async (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const body = await c.req.json();
        if (!body.name) {
            return c.json({ error: 'Missing folder name' }, 400);
        }
        if (!DEFAULT_ALLOWED_FOLDERS.includes(body.name)) {
            return c.json({ error: `Invalid folder name: ${body.name}. Allowed: ${DEFAULT_ALLOWED_FOLDERS.join(', ')}` }, 400);
        }
        // Ensure vault exists and folder is created
        initVault(dir);
        return c.json({ ok: true, folder: body.name }, 201);
    });
    // DELETE /:id — Remove entry + physical file
    app.delete('/:id', (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const id = c.req.param('id');
        const removed = removeEntry(dir, id);
        if (!removed) {
            return c.json({ error: 'Entry not found' }, 404);
        }
        return c.json({ ok: true, id });
    });
    // PATCH /:id — Update metadata (tags, description, folder)
    app.patch('/:id', async (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const id = c.req.param('id');
        const body = await c.req.json();
        try {
            const entry = updateEntry(dir, id, body);
            if (!entry) {
                return c.json({ error: 'Entry not found' }, 404);
            }
            return c.json({ entry });
        }
        catch (err) {
            const message = err instanceof Error ? err.message : 'Update failed';
            return c.json({ error: message }, 400);
        }
    });
    // GET /:id/content — Download/stream file
    app.get('/:id/content', (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const id = c.req.param('id');
        const manifest = readManifest(dir);
        const entry = manifest.entries.find((e) => e.id === id);
        if (!entry) {
            return c.json({ error: 'Entry not found' }, 404);
        }
        const filePath = getEntryFile(dir, id);
        if (!filePath) {
            return c.json({ error: 'File not found on disk' }, 404);
        }
        const stat = statSync(filePath);
        const stream = createReadStream(filePath);
        const webStream = Readable.toWeb(stream);
        c.header('Content-Type', entry.mimeType);
        c.header('Content-Disposition', `attachment; filename="${entry.filename}"`);
        c.header('Content-Length', String(stat.size));
        return c.body(webStream);
    });
    // GET /:id/transcript — Get transcript entry content or 404
    app.get('/:id/transcript', (c) => {
        const dir = getWorkspaceCwd(c, cwd);
        const id = c.req.param('id');
        const manifest = readManifest(dir);
        const entry = manifest.entries.find((e) => e.id === id);
        if (!entry) {
            return c.json({ error: 'Entry not found' }, 404);
        }
        if (!entry.transcriptId) {
            return c.json({ error: 'No transcript associated with this entry' }, 404);
        }
        // Look up the transcript entry
        const transcriptEntry = manifest.entries.find((e) => e.id === entry.transcriptId);
        if (!transcriptEntry) {
            return c.json({ error: 'Transcript entry not found' }, 404);
        }
        const filePath = getEntryFile(dir, transcriptEntry.id);
        if (!filePath) {
            return c.json({ error: 'Transcript file not found on disk' }, 404);
        }
        const content = readFileSync(filePath, 'utf-8');
        return c.json({ transcriptId: transcriptEntry.id, content });
    });
    return app;
}
//# sourceMappingURL=context.js.map