const { test, expect } = require('@playwright/test')
const { Ftp } = require('../../src/app/server/session-ftp')
const { spawn } = require('child_process')
const path = require('path')

let ftpServer

test.describe('Ftp Class', () => {
  test.beforeAll(async () => {
    // Start the FTP test server
    const serverPath = path.join(__dirname, '../e2e/common/ftp.js')
    ftpServer = spawn('node', [serverPath])

    await new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        reject(new Error('FTP server start timeout'))
      }, 5000)

      ftpServer.stdout.on('data', (data) => {
        if (data.toString().includes('FTP server is running at port 21')) {
          clearTimeout(timeout)
          resolve()
        }
      })

      ftpServer.stderr.on('data', (data) => {
        console.error(`FTP server error: ${data}`)
      })
    })
  }, { timeout: 10000 }) // Increase timeout to 10 seconds

  test.afterAll(async () => {
    // Stop the FTP test server
    ftpServer.kill()
    await new Promise((resolve) => ftpServer.on('close', resolve))
  })

  let ftp

  test.beforeEach(async () => {
    const initOptions = {
      host: 'localhost',
      port: 21,
      user: 'test',
      password: 'test123'
    }
    ftp = new Ftp(initOptions)
    await ftp.connect(initOptions)
  })

  test.afterEach(() => {
    if (ftp) {
      ftp.kill()
    }
  })

  test('should connect to FTP server', async () => {
    expect(ftp.client).toBeTruthy()
  })

  test('should get home directory', async () => {
    const homeDir = await ftp.getHomeDir()
    expect(typeof homeDir).toBe('string')
  })

  test('should create and remove a directory', async () => {
    const testDir = '/test-dir'
    await ftp.mkdir(testDir)
    let list = await ftp.list('/')
    expect(list.some(item => item.name === 'test-dir')).toBeTruthy()

    await ftp.rmdir(testDir)
    list = await ftp.list('/')
    expect(list.some(item => item.name === 'test-dir')).toBeFalsy()
  })

  test('should create and remove a file', async () => {
    const testFile = '/test-file.txt'
    await ftp.touch(testFile)
    let list = await ftp.list('/')
    expect(list.some(item => item.name === 'test-file.txt')).toBeTruthy()

    await ftp.rm(testFile)
    list = await ftp.list('/')
    expect(list.some(item => item.name === 'test-file.txt')).toBeFalsy()
  })

  test('should write and read a file', async () => {
    const testFile = '/test-file.txt'
    const testContent = 'Hello, FTP!'

    console.log('Starting write operation')
    await ftp.writeFile(testFile, testContent)
    console.log('Write operation completed')

    console.log('Starting read operation')
    const content = await ftp.readFile(testFile)
    console.log('Read operation completed')

    expect(content.toString()).toBe(testContent)

    console.log('Starting delete operation')
    await ftp.rm(testFile)
    console.log('Delete operation completed')
  })

  test('should rename a file', async () => {
    const oldName = '/old-file.txt'
    const newName = '/new-file.txt'
    await ftp.touch(oldName)
    await ftp.rename(oldName, newName)

    const list = await ftp.list('/')
    expect(list.some(item => item.name === 'new-file.txt')).toBeTruthy()
    expect(list.some(item => item.name === 'old-file.txt')).toBeFalsy()

    await ftp.rm(newName)
  })

  test('should get file stats', async () => {
    const testFile = '/test-file.txt'
    await ftp.touch(testFile)

    const stats = await ftp.stat(testFile)
    expect(stats).toHaveProperty('size')
    expect(stats).toHaveProperty('modifyTime')
    expect(stats).toHaveProperty('isDirectory')

    await ftp.rm(testFile)
  })
})
