import { type Application, type Request, type Response } from 'express';
import { existsSync, readdirSync, statSync } from 'fs';
import { resolve, sep } from 'path';
import { Repository } from '../db/repository.js';
import { logger } from '../logger.js';
import { parseTaskId } from './validation.js';
import { canViewTask } from './local-api-helpers.js';

export function mountSubtaskFilesApi(app: Application, repo: Repository): void {

  // NOTE: listing MUST be registered before the wildcard route
  app.get('/api/local/tasks/:id/subtasks/:jobId/files', async (req: Request, res: Response) => {
    try {
      const taskId = parseTaskId(req.params.id);
      if (taskId === null) {
        res.status(400).json({ error: 'Invalid task ID' });
        return;
      }
      const jobId = req.params.jobId;

      const viewer = (req.user as Express.User | undefined) ?? undefined;
      const task = await repo.getLocalTask(taskId, viewer ? { viewer } : undefined);
      if (!canViewTask(req, res, task)) return;

      // jobId で直接取得（孫タスクにも対応）
      const subJob = await repo.getJob(jobId, viewer ? { viewer } : undefined);
      if (!subJob || !subJob.worktreePath) {
        res.status(404).json({ error: 'Subtask not found' }); return;
      }

      // タスクのワークスペース配下であることを確認
      if (task!.workspacePath && !subJob.worktreePath.startsWith(task!.workspacePath)) {
        res.status(404).json({ error: 'Subtask not found' }); return;
      }

      const basePath = resolve(subJob.worktreePath);
      const categories: Record<string, string[]> = {};
      for (const dir of ['output', 'logs', 'input']) {
        const dirPath = resolve(basePath, dir);
        if (!existsSync(dirPath)) continue;
        const dirFiles = readdirSync(dirPath, { recursive: true })
          .map(f => String(f))
          .filter(f => !statSync(resolve(dirPath, f)).isDirectory());
        if (dirFiles.length > 0) categories[dir] = dirFiles;
      }

      // 後方互換: files は output/ のファイル一覧
      res.json({ files: categories['output'] ?? [], categories });
    } catch (err) {
      logger.error(`Subtask file list API error: ${err}`);
      res.status(500).json({ error: 'Failed to list subtask files' });
    }
  });

  app.get('/api/local/tasks/:id/subtasks/:jobId/files/*', async (req: Request, res: Response) => {
    try {
      const taskId = parseTaskId(req.params.id);
      if (taskId === null) {
        res.status(400).json({ error: 'Invalid task ID' });
        return;
      }
      const jobId = req.params.jobId;
      const filePath = req.params[0];

      const viewer = (req.user as Express.User | undefined) ?? undefined;
      const task = await repo.getLocalTask(taskId, viewer ? { viewer } : undefined);
      if (!canViewTask(req, res, task)) return;

      // jobId で直接取得（孫タスクにも対応）
      const subJob = await repo.getJob(jobId, viewer ? { viewer } : undefined);
      if (!subJob || !subJob.worktreePath) {
        res.status(404).json({ error: 'Subtask not found' }); return;
      }

      // タスクのワークスペース配下であることを確認
      if (task!.workspacePath && !subJob.worktreePath.startsWith(task!.workspacePath)) {
        res.status(404).json({ error: 'Subtask not found' }); return;
      }

      const base = resolve(subJob.worktreePath);
      const resolved = resolve(base, filePath);
      // Require the trailing separator so a sibling like `<base>-x` cannot pass
      // the prefix check; allow the base dir itself.
      if (resolved !== base && !resolved.startsWith(base + sep)) {
        res.status(403).json({ error: 'Access denied' }); return;
      }

      if (!existsSync(resolved)) { res.status(404).json({ error: 'File not found' }); return; }

      const stat = statSync(resolved);
      if (stat.isDirectory()) {
        const dirFiles = readdirSync(resolved);
        res.json({ files: dirFiles }); return;
      }

      res.sendFile(resolved);
    } catch (err) {
      logger.error(`Subtask files API error: ${err}`);
      res.status(500).json({ error: 'Failed to fetch subtask file' });
    }
  });
}
