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

test.describe('FtpTransfer Class', () => {
  let ftpServer
  let ftp

  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()
        }
      })
    })
  })

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

  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 handle file transfer events', async () => {
    const localPath = path.join(__dirname, 'test-upload.txt')
    const remotePath = '/test-upload.txt'
    const testContent = 'x'.repeat(1024 * 1024) // 1MB file
    let dataEventCalled = false
    let endEventCalled = false

    await fs.promises.writeFile(localPath, testContent)

    const transfer = new Transfer({
      remotePath,
      localPath,
      type: 'upload',
      sftp: ftp.client,
      sftpId: '1',
      sessionId: '1',
      id: '1',
      options: {
        ftp: true
      },
      ws: {
        s: (event) => {
          if (event.id.startsWith('transfer:data:')) {
            dataEventCalled = true
          }
          if (event.id.startsWith('transfer:end:')) {
            endEventCalled = true
          }
        },
        close: () => {}
      }
    })
    console.log('transfer', transfer)
    await transfer.start()
    await new Promise(resolve => setTimeout(resolve, 1000))

    expect(dataEventCalled).toBe(true)
    expect(endEventCalled).toBe(true)

    await ftp.rm(remotePath)
    await fs.promises.unlink(localPath)
  })

  test('should pause and resume transfer', async () => {
    const transfer = new Transfer({
      remotePath: '/test.txt',
      localPath: 'test.txt',
      type: 'upload',
      sftp: ftp.client,
      id: '1',
      ws: {
        s: () => {},
        close: () => {}
      }
    })

    transfer.pause()
    expect(transfer.pausing).toBe(true)

    transfer.resume()
    expect(transfer.pausing).toBe(false)
  })

  test('should properly destroy transfer', async () => {
    const transfer = new Transfer({
      remotePath: '/test.txt',
      localPath: 'test.txt',
      type: 'upload',
      sftp: ftp.client,
      id: '1',
      ws: {
        s: () => {},
        close: () => {}
      }
    })

    transfer.destroy()
    await new Promise(resolve => setTimeout(resolve, 300))
    expect(transfer.onDestroy).toBe(true)
    expect(transfer.src).toBe(null)
    expect(transfer.dst).toBe(null)
    expect(transfer.ftpClient).toBe(null)
  })

  test('should handle transfer errors', async () => {
    let errorCalled = false
    const transfer = new Transfer({
      remotePath: '/nonexistent/path/test.txt',
      localPath: 'test.txt',
      type: 'upload',
      sftp: ftp.client,
      id: '1',
      ws: {
        s: (event) => {
          if (event.id.startsWith('transfer:err:')) {
            errorCalled = true
          }
        },
        close: () => {}
      }
    })

    await transfer.start()
    await new Promise(resolve => setTimeout(resolve, 1000))
    expect(errorCalled).toBe(true)
  })
})
