/**
 * Files Route 测试
 *
 * 测试文件浏览器 REST API 端点
 */

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { Hono } from 'hono';
import {
  filesRouter,
  setWorkingDirectory,
  getWorkingDirectory,
} from '../../../src/routes/files.js';
import { join } from 'node:path';

// Create test app
const app = new Hono();
app.route('/files', filesRouter);

// Save original working directory
const originalWorkdir = process.cwd();

describe('Files Route', () => {
  beforeEach(() => {
    // Reset to current working directory
    setWorkingDirectory(originalWorkdir);
  });

  afterEach(() => {
    // Restore original working directory
    setWorkingDirectory(originalWorkdir);
  });

  describe('setWorkingDirectory / getWorkingDirectory', () => {
    it('设置工作目录', () => {
      setWorkingDirectory('/tmp');
      expect(getWorkingDirectory()).toBe('/tmp');
    });

    it('获取当前工作目录', () => {
      expect(getWorkingDirectory()).toBeDefined();
      expect(typeof getWorkingDirectory()).toBe('string');
    });
  });

  describe('GET /files - 获取工作目录信息', () => {
    it('返回工作目录信息', async () => {
      const res = await app.request('/files');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.workingDirectory).toBeDefined();
      expect(json.data.separator).toBe('/');
    });
  });

  describe('GET /files/list - 列出目录内容', () => {
    it('列出当前目录', async () => {
      const res = await app.request('/files/list');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(Array.isArray(json.data.files)).toBe(true);
    });

    it('列出指定目录', async () => {
      const res = await app.request('/files/list?path=.');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.path).toBe('.');
    });

    it('包含隐藏文件', async () => {
      const res = await app.request('/files/list?path=.&hidden=true');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('路径在工作目录外返回 403', async () => {
      const res = await app.request('/files/list?path=../../../../../../etc');
      const json = await res.json();

      expect(res.status).toBe(403);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Access denied');
    });

    it('非目录返回 400', async () => {
      // package.json 是一个文件，不是目录
      const res = await app.request('/files/list?path=package.json');
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Not a directory');
    });

    it('文件信息包含正确字段', async () => {
      const res = await app.request('/files/list?path=.');
      const json = await res.json();

      expect(res.status).toBe(200);
      if (json.data.files.length > 0) {
        const file = json.data.files[0];
        expect(file).toHaveProperty('name');
        expect(file).toHaveProperty('path');
        expect(file).toHaveProperty('type');
        expect(file).toHaveProperty('size');
        expect(file).toHaveProperty('modified');
      }
    });
  });

  describe('GET /files/read - 读取文件内容', () => {
    it('缺少路径参数返回 400', async () => {
      const res = await app.request('/files/read');
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Path is required');
    });

    it('读取文本文件', async () => {
      const res = await app.request('/files/read?path=package.json');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.encoding).toBe('utf-8');
      expect(json.data.content).toContain('"name"');
    });

    it('路径在工作目录外返回 403', async () => {
      const res = await app.request('/files/read?path=../../../../../../etc/passwd');
      const json = await res.json();

      expect(res.status).toBe(403);
      expect(json.success).toBe(false);
    });

    it('读取目录返回 400', async () => {
      const res = await app.request('/files/read?path=src');
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.error).toContain('Cannot read directory');
    });

    it('返回文件元信息', async () => {
      const res = await app.request('/files/read?path=package.json');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toHaveProperty('path');
      expect(json.data).toHaveProperty('name');
      expect(json.data).toHaveProperty('type');
      expect(json.data).toHaveProperty('size');
      expect(json.data).toHaveProperty('modified');
    });
  });

  describe('GET /files/stat - 获取文件信息', () => {
    it('缺少路径参数返回 400', async () => {
      const res = await app.request('/files/stat');
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Path is required');
    });

    it('获取文件信息', async () => {
      const res = await app.request('/files/stat?path=package.json');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.type).toBe('file');
      expect(json.data.name).toBe('package.json');
    });

    it('获取目录信息', async () => {
      const res = await app.request('/files/stat?path=src');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.type).toBe('directory');
    });

    it('路径在工作目录外返回 403', async () => {
      const res = await app.request('/files/stat?path=../../../../../../etc/passwd');
      const json = await res.json();

      expect(res.status).toBe(403);
      expect(json.success).toBe(false);
    });

    it('文件不存在返回 500', async () => {
      const res = await app.request('/files/stat?path=non-existent-file-12345.txt');
      const json = await res.json();

      expect(res.status).toBe(500);
      expect(json.success).toBe(false);
    });
  });

  describe('GET /files/tree - 获取目录树', () => {
    it('获取目录树', async () => {
      const res = await app.request('/files/tree?path=.&depth=1');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.path).toBe('.');
      expect(Array.isArray(json.data.tree)).toBe(true);
    });

    it('限制深度', async () => {
      const res = await app.request('/files/tree?path=.&depth=2');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('显示隐藏文件', async () => {
      const res = await app.request('/files/tree?path=.&depth=1&hidden=true');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('路径在工作目录外返回 403', async () => {
      const res = await app.request('/files/tree?path=../../../../../../etc');
      const json = await res.json();

      expect(res.status).toBe(403);
      expect(json.success).toBe(false);
    });

    it('树节点包含正确字段', async () => {
      const res = await app.request('/files/tree?path=.&depth=1');
      const json = await res.json();

      expect(res.status).toBe(200);
      if (json.data.tree.length > 0) {
        const node = json.data.tree[0];
        expect(node).toHaveProperty('name');
        expect(node).toHaveProperty('path');
        expect(node).toHaveProperty('type');
      }
    });
  });
});
