import logger from 'morgan'
import { viewPath, env, staticPaths, pack, isProd, cwd } from './common.js'
import express from 'express'
import { createServer as createViteServer } from 'vite'
import conf from './conf.js'
import copy from 'json-deep-copy'
import fs from 'fs'
import path from 'path'
import { spawn } from 'child_process'
import multer from 'multer'

const devPort = env.DEV_PORT || 5570
const host = env.DEV_HOST || '127.0.0.1'
const h = `http://${host}:${devPort}`
const defaultAIPreset = {
  baseURLAI: 'https://ai.electerm.org/api/ai',
  apiPathAI: '/chat/completions',
  modelAI: 'mistral-small-latest',
  authHeaderNameAI: 'Authorization: Bearer',
  id: 'ai.electerm.org',
  nameAI: 'ai.electerm.org(default free)'
}

const base = {
  version: pack.version,
  isDev: !isProd,
  siteName: pack.name,
  defaultAIPreset
}

function handleIndex (req, res) {
  const view = 'index'
  res.render(view, {
    ...base,
    _global: copy(base)
  })
}

function redirect (req, res) {
  const {
    name
  } = req.params
  const mapper = {
    electerm: '/src/client/entry/electerm.jsx',
    worker: '/src/client/entry/worker.js'
  }
  res.redirect(mapper[name])
}

async function createServer () {
  const app = express()

  // Create Vite server in middleware mode and configure the app type as
  // 'custom', disabling Vite's own HTML serving logic so parent server
  // can take control
  const vite = await createViteServer({
    ...conf,
    server: {
      middlewareMode: true,
      hmr: {
        port: 30085,
        overlay: true
      }
    },
    appType: 'custom'
  })

  app.use(
    logger('dev')
  )
  app.use(express.json())
  app.use(express.urlencoded({
    extended: true
  }))
  staticPaths.forEach(({ path, dir }) => {
    app.use(
      path,
      express.static(dir, { maxAge: '170d' })
    )
  })

  const upload = multer({ dest: 'uploads/' })

  app.get('/api/download', (req, res) => {
    const filePath = req.query.path
    if (!filePath) {
      return res.status(400).json({ error: 'path is required' })
    }
    try {
      const stat = fs.statSync(filePath)
      if (stat.isFile()) {
        const fileName = path.basename(filePath)
        res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(fileName)}"`)
        res.setHeader('Content-Type', 'application/octet-stream')
        fs.createReadStream(filePath).pipe(res)
      } else if (stat.isDirectory()) {
        const dirName = path.basename(filePath)
        const parentDir = path.dirname(filePath)
        res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(dirName)}.tar.gz"`)
        res.setHeader('Content-Type', 'application/gzip')
        const tar = spawn('tar', ['czf', '-', '-C', parentDir, dirName])
        tar.stdout.pipe(res)
        tar.stderr.on('data', (data) => {
          console.error('tar stderr:', data.toString())
        })
        tar.on('error', (err) => {
          console.error('tar error:', err)
          if (!res.headersSent) {
            res.status(500).json({ error: err.message })
          }
        })
      } else {
        res.status(400).json({ error: 'path is not a file or directory' })
      }
    } catch (err) {
      console.error('download error:', err)
      res.status(500).json({ error: err.message })
    }
  })

  app.post('/api/upload', upload.single('file'), (req, res) => {
    const targetDir = req.body.path
    if (!targetDir || !req.file) {
      return res.status(400).json({ error: 'path and file are required' })
    }
    try {
      const destPath = path.join(targetDir, req.file.originalname)
      fs.renameSync(req.file.path, destPath)
      res.json({ success: true, path: destPath })
    } catch (err) {
      console.error('upload error:', err)
      res.status(500).json({ error: err.message })
    }
  })

  app.set('views', viewPath)
  app.set('view engine', 'pug')

  // Use vite's connect instance as middleware. If you use your own
  // express router (express.Router()), you should use router.use
  app.use(vite.middlewares)
  app.get(['/', '/index.html'], handleIndex)
  app.get('/:dir/:name.:ext', redirect)
  app.listen(devPort, host, () => {
    console.log('cwd:', cwd)
    console.log(`server started at ${h}`)
  })
}

createServer()
