import Dockerode from "dockerode"
import LogUtil, { sendProjectStatus, sendSocketMessage } from "~/server/utils/log"
import fs from 'fs'
import path from 'path'
import { changeProjectStatus } from "~/server/utils/postgres"

export default defineEventHandler(async (event) => {
  let username = event.context.username
  let isClonedSuccess = true
  let sshKey = ''
  try {
    LogUtil.clear(username)
    let docker = createDockerFactory(username)
    let container: Dockerode.Container = {} as Dockerode.Container
    const port = (await getPgTableData( 'user', username))?.port
    const row = await getPgTableData('v2', username)
    if (!row) await insertPgTableData('v2', username)
    await changeProjectStatus( 'v2', username, 'status', 'creating')
    // 必须要保证创建容器是首先执行
    // node 容器根据 dev/prod 环境与否,决定在哪里创建,远程容器还是本机容器
    await LogUtil.run(username, '创建 node 容器', async () => {
      container = await docker.checkAndCreateContainer({
        name: username + '.node',
        img: 'node:16-bullseye',
        exposedPorts: { '8080/tcp': {} },
        portBindings: { '8080/tcp': [{ HostPort: port }]  }
      })
      await docker.startContainer({ container })
    })
    await LogUtil.run(username, '检查 SSH Key', async () => {
      sshKey = await checkSshExists(username)
      LogUtil.printWarning(username, `${username}@greaconsulting.com 用户 SSH key 为 <strong>${sshKey.replace(/\n/g, '')}</strong>, 若克隆仓库失败, 请检查是否放入 Gitlab SSH 设置中并重试\n`)
    })
    // 创建 postgres 不一定要在本机,即使是 dev 环境也可以联远程的容器
    await LogUtil.run(username, '配置 postgres 容器', async () => {
      let postgres = await docker.checkContainer('postgres_12')
      if (!postgres) {
        postgres = await docker.checkAndCreateContainer({ name: 'postgres_12', img: 'postgres:12', env: ["POSTGRES_PASSWORD=postgres"], portBindings: { '5432/tcp': [{ HostPort: PgPort.toString() }] } })
        await docker.startContainer({ container: postgres })
        await sleep(3000)
      }
      
      let client = await createPgClientFactory()
      let result = await executePgQuery({ client, query: "SELECT u.datname  FROM pg_catalog.pg_database u where u.datname='" +username+ "';" })
      if (result.rows.length === 0) {
        await executePgQuery({ client, query: 'CREATE DATABASE ' + username})
        await stopPgClient(client)
        client = await createPgClientFactory(username)
        await executePgQuery({ client, query: 'CREATE SCHEMA library' })
        await stopPgClient(client)
      }
    })
    await LogUtil.run(username, '创建 redis 容器', async () => {
      if (process.env.NODE_ENV?.trim() !== 'production') {
        let redisInfo = await docker.checkContainer('redis')
        if (!redisInfo) {
          let redis = await docker.checkAndCreateContainer({ name: 'redis', img: 'redis', portBindings: { '6379/tcp': [{ HostPort: '6379' }] } })
          await docker.startContainer({ container: redis })
        }
      }
    })
    await LogUtil.run(username, '创建 zookeeper 容器', async () => {
      if (process.env.NODE_ENV?.trim() !== 'production') {
        let zookeeper = await docker.checkAndCreateContainer({ name: 'zookeeper', img: 'zookeeper', portBindings: { '2181/tcp': [{ HostPort:  '2181' }] } })
        await docker.startContainer({ container: zookeeper })
      }
    })

    // 检查本机 rocketmq 端口是否被占用,被占用说明已经有 rockqtmq 服务启动,这时候就不安装容器了
    await LogUtil.run(username, '创建 rocketmq serv 容器', async () => {
      if (process.env.NODE_ENV?.trim() !== 'production') {
        let rockermqsrv = await docker.checkAndCreateContainer({ name: 'rocketmq.srv', img: 'foxiswho/rocketmq:4.8.0', portBindings: { '9876/tcp': [{ 'HostPort': '9876' }] /** , '10909/tcp': [], '10911/tcp': [], '10912/tcp': []*/ }, env: ['JAVA_OPT_EXT=-Xms512M -Xmx512M -Xmn128m'] , cmd: ['bash', '-c', 'mqnamesrv'] })
        await docker.startContainer({ container: rockermqsrv })
      }
    })

    await LogUtil.run(username, '创建 rocketmq broker 容器', async () => {
      if (process.env.NODE_ENV?.trim() !== 'production') {
        let rocketmqbroker = await docker.checkAndCreateContainer({ name: 'rocketmq.broker', img: 'foxiswho/rocketmq:4.8.0', portBindings: { '10909/tcp': [{ 'HostPort': '10909' }], '10911/tcp': [{ 'HostPort': '10911' }] /** , '9876/tcp': [],'10912/tcp': [] */ }, env: ['JAVA_OPT_EXT=-Xms512M -Xmx512M -Xmn128m'] })
        await docker.startContainer({ container: rocketmqbroker })

        let info = await rocketmqbroker.inspect()
        if (info?.State.Status === 'created') {
          let brokerText = fs.readFileSync(path.resolve('./public/files/v2/broker.conf'), { encoding: 'utf-8' })
          await docker.execContainerCommand({ container: rocketmqbroker, cmd: 'mkdir /home/rocketmq/conf -p' })
          await docker.execContainerCommand({ container: rocketmqbroker, cmd: 'touch /home/rocketmq/conf/broker.conf' })
          await docker.writeFile({ container: rocketmqbroker, path: '/home/rocketmq/conf/broker.conf', text: "'" +brokerText + "'" })
          await docker.execContainerCommand({ container: rocketmqbroker, cmd: 'mqbroker -c /home/rocketmq/conf/broker.conf' })
        }
      }
    })

    await LogUtil.run(username, '克隆仓库', async () => {
      isClonedSuccess = false
      await docker.execContainerCommand({ container, cmd: ['git', 'config' ,'--global', 'core.sshCommand', 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'] })
      await docker.execContainerCommand({ container, cmd: 'rm -rf /var/logwire-backend' })
      await docker.execContainerCommand({ container, cmd: 'git clone ssh://git@gitlab.logwire.cn:13389/logwire2/logwire-backend.git', dir: '/var' })
      isClonedSuccess = true
    })
    // await LogUtil.run(username, '添加源', async () => {
    //   let txt = await docker.getFile({ container, path: '/etc/apt/sources.list' })
    //   if (txt && !txt.includes('deb http://security.debian.org/debian-security bullseye-security main')) {
    //     await docker.appendFile({ container, path: '/etc/apt/sources.list', text: '\'deb http://security.debian.org/debian-security bullseye-security main\'' })
    //   }
    // })
    await LogUtil.run(username, '更新源', async () => {
      await docker.execContainerCommand({ container, cmd: 'apt-get update' })
    })
    await LogUtil.run(username, '安装 openjdk ', async () => {
      const openjdkFilePath = '/var/openlogic-openjdk-17.0.10+7-linux-x64.tar.gz'
      const stat = fs.statSync(openjdkFilePath, { throwIfNoEntry: false })
      if (!stat) {
        throw new Error('未找到 ' + openjdkFilePath + ', 请下载文件并放置到根目录 var 文件夹内')
      }
      await docker.putArchive({ container, tarPath: openjdkFilePath , targetPath: '/var' })
      await docker.execContainerCommand({ container, cmd: 'cp -r openlogic-openjdk-17.0.10+7-linux-x64/ java-17-openjdk', dir: '/var' })
      await docker.execContainerCommand({ container, cmd: 'rm -rf openlogic-openjdk-17.0.10+7-linux-x64', dir: '/var' })
      await docker.execContainerCommand({ container, cmd: 'ln -sf /var/java-17-openjdk/bin/java /usr/bin/java' })
      // await docker.execContainerCommand({ container, cmd: 'ln -s /etc/alternatives/java /usr/bin/java' })
      // await docker.execContainerCommand({ container, cmd: 'apt-get install -y openjdk-17-jdk' })
    })
    await LogUtil.run(username, '安装 maven ', async () => {
      await docker.execContainerCommand({ container, cmd: 'apt-get install -y maven' })
    })
    await LogUtil.run(username, '修改 maven 源', async () => {
      let mavenSettingXml = fs.readFileSync(path.resolve('./public/files/settings.xml'), { encoding: 'utf-8' })
      await docker.writeFile({ container, path: '/etc/maven/settings.xml', text: '\'' + mavenSettingXml + '\'' })

      let mavenSecurityXml = fs.readFileSync(path.resolve('./public/files/settings-security.xml'), { encoding: 'utf-8' })
      try {
        let xml = await docker.getFile({ container, path: '/root/.m2/settings-security.xml' })
      } catch (err) {
        await docker.execContainerCommand({ container, cmd: 'mkdir .m2', dir: '/root' })
        await docker.writeFile({ container, path: '/root/.m2/settings-security.xml', text: '\'' + mavenSecurityXml + '\'' })
      }
    })
    // wetty 不好用,去掉了,逃生通道留一个 VSCODE 即可
    await LogUtil.run(username, '安装 code-server ', async () => {
      try {
        let result = await docker.execContainerCommand({ container, cmd: 'which code-server' })
      } catch (err) {
        await docker.execContainerCommand({ container, cmd: 'apt-get install -y build-essential pkg-config python3' })
        await docker.execContainerCommand({ container, cmd: 'npm config set python python3' })
        await docker.execContainerCommand({ container, cmd: 'yarn global add code-server@4.6.0' })
      }
    })
    await LogUtil.run(username, '安装 nginx ', async () => {
      await docker.execContainerCommand({ container, cmd: 'apt-get install -y nginx'})
    })
    await LogUtil.run(username, '安装 pm2 ', async () => {
      await docker.execContainerCommand({ container, cmd: 'npm install --global pm2' })
    })
    await LogUtil.run(username, '安装 zip', async () => {
      await docker.execContainerCommand({ container, cmd: 'apt-get install -y zip' })
    })
    await LogUtil.run(username, '配置 nginx ', async () => {
      let nginxConfigText = fs.readFileSync(path.resolve('./public/files/nginx.conf'), { encoding: 'utf-8' })
      await docker.writeFile({ container, path: '/etc/nginx/nginx.conf', text: '\'' + nginxConfigText + '\'' })
    })
    await LogUtil.run(username, '启动 code-server ', async () => {
      try {
        let result = await docker.execContainerCommand({ container, cmd: 'lsof -i:8000' })
      } catch (err) {
        try {
          docker.execContainerCommand({ container, cmd: 'code-server --bind-addr 127.0.0.1:8000 --auth none' })
        } catch (err) {
          console.log('code-server err', err)
        }
      }
    })
    await LogUtil.run(username, '启动 nginx ', async () => {
      try {
        let result = await docker.execContainerCommand({ container, cmd: 'lsof -i:80' })
      } catch (err) {
        try {
          await docker.execContainerCommand({ container, cmd: 'nginx' })
        } catch (err) {
          console.log('nginx err', err)
        }
      }
    })
    await LogUtil.run(username, '配置租户信息', async () => {
      const tenants = {
        id: username,
        host: 'a.test.com:23335,a.test.com:23336',
        'database-schema': 'library'
      }
      await setPgTableData('v2', username, 'tenants', JSON.stringify(tenants))
    })
    await LogUtil.run(username, '配置调试信息', async () => {
      const debug = {
        host: '192.168.1.94'
      }
      await setPgTableData('v2', username, 'debug', JSON.stringify(debug))
    })
    await changeProjectStatus( 'v2', username, 'status', 'created')
    LogUtil.printSuccess(username, '安装成功')
  } catch (err: any) {
    await changeProjectStatus( 'v2', username, 'status', 'null')
    if (!isClonedSuccess) {
      const message = `初始化中克隆仓库失败,请将 <strong>${sshKey.replace(/\n/g, '')}</strong> 放入 Gitlab SSH 设置中并重试`
      const type = 'Tip'
      const eventData = { type, message }
      sendSocketMessage(username, 'v2', JSON.stringify(eventData))
    }
    LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
    setResponseStatus(event, 500)
    return err
  }
})