import 'dotenv/config'
import express from 'express'
import mysql from 'mysql2/promise'
import path from 'node:path'
import { existsSync } from 'node:fs'
import { fileURLToPath } from 'node:url'

const app = express()
const port = Number(process.env.PORT ?? process.env.SERVER_PORT ?? 8788)
const matchTableName = process.env.DB_TABLE ?? 'badminton'
const historyTableName = process.env.DB_HISTORY_TABLE ?? 'history'
const appVersion = process.env.APP_VERSION ?? `${Date.now()}`
const appStartedAt = new Date().toISOString()

const currentFilePath = fileURLToPath(import.meta.url)
const currentDir = path.dirname(currentFilePath)
const projectRoot = path.resolve(currentDir, '..')
const distDir = path.join(projectRoot, 'dist')
const distReady = existsSync(path.join(distDir, 'index.html'))

const requiredEnv = ['DB_HOST', 'DB_PORT', 'DB_USER', 'DB_PASSWORD', 'DB_DATABASE']
const missingEnv = requiredEnv.filter((key) => !process.env[key])

const pool =
  missingEnv.length === 0
    ? mysql.createPool({
        host: process.env.DB_HOST,
        port: Number(process.env.DB_PORT),
        user: process.env.DB_USER,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_DATABASE,
        charset: 'utf8mb4',
        waitForConnections: true,
        connectionLimit: 10,
      })
    : null

app.use(express.json())

app.get('/api/health', (_request, response) => {
  response.json({
    appStartedAt,
    appVersion,
    ok: true,
    dbReady: Boolean(pool),
    distReady,
    historyTableName,
    matchTableName,
    missingEnv,
  })
})

app.get('/api/version', (_request, response) => {
  response.set({
    'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
    Expires: '0',
    Pragma: 'no-cache',
    'Surrogate-Control': 'no-store',
  })

  response.json({
    ok: true,
    startedAt: appStartedAt,
    version: appVersion,
  })
})

app.get('/api/match-results/:time', async (request, response) => {
  if (!pool) {
    response.status(500).json({
      ok: false,
      message: `DB 尚未設定完成，缺少 ${missingEnv.join(', ')}`,
    })
    return
  }

  const time = String(request.params.time ?? '')

  if (!/^\d{8}$/.test(time)) {
    response.status(400).json({
      ok: false,
      message: '日期格式必須是 YYYYMMDD。',
    })
    return
  }

  try {
    await ensureMatchTable(pool, matchTableName)
    const [rows] = await pool.execute(
      `SELECT time, personnel, battlecombination FROM \`${matchTableName}\` WHERE time = ? LIMIT 1`,
      [Number(time)],
    )

    const record = rows[0]

    if (!record) {
      response.status(404).json({
        ok: false,
        message: '指定日期沒有資料。',
      })
      return
    }

    response.json({
      ok: true,
      data: record,
    })
  } catch (error) {
    console.error('match-results load error:', error)
    response.status(500).json({
      ok: false,
      message: error instanceof Error ? error.message : '讀取對戰資料失敗。',
    })
  }
})

app.post('/api/history', async (request, response) => {
  if (!pool) {
    response.status(500).json({
      ok: false,
      message: `DB 尚未設定完成，缺少 ${missingEnv.join(', ')}`,
    })
    return
  }

  const {
    dayOfWeek,
    players,
    score,
    scoreList,
    team,
    time,
    type,
    winScore,
  } = request.body ?? {}

  if (
    typeof time !== 'number' ||
    typeof dayOfWeek !== 'number' ||
    typeof winScore !== 'number' ||
    typeof type !== 'number' ||
    !Array.isArray(score) ||
    score.length !== 2 ||
    !Array.isArray(players) ||
    !Array.isArray(team) ||
    !Array.isArray(scoreList)
  ) {
    response.status(400).json({
      ok: false,
      message: '戰績資料格式不正確。',
    })
    return
  }

  try {
    await ensureHistoryTable(pool, historyTableName)
    const [result] = await pool.execute(
      `
        INSERT INTO \`${historyTableName}\`
          (time, dayOfWeek, score, winScore, type, players, team, scoreList)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
      `,
      [
        time,
        dayOfWeek,
        JSON.stringify(score),
        winScore,
        type,
        JSON.stringify(players),
        JSON.stringify(team),
        JSON.stringify(scoreList),
      ],
    )

    response.json({
      ok: true,
      data: {
        id: result.insertId,
      },
      message: '戰績已寫入 DB。',
    })
  } catch (error) {
    console.error('history save error:', error)
    response.status(500).json({
      ok: false,
      message: error instanceof Error ? error.message : '寫入戰績失敗。',
    })
  }
})

app.get('/api/history', async (_request, response) => {
  if (!pool) {
    response.status(500).json({
      ok: false,
      message: `DB 尚未設定完成，缺少 ${missingEnv.join(', ')}`,
    })
    return
  }

  try {
    await ensureHistoryTable(pool, historyTableName)
    const [rows] = await pool.execute(
      `
        SELECT id, time, dayOfWeek, score, winScore, type, players, team, scoreList
        FROM \`${historyTableName}\`
        ORDER BY id DESC
      `,
    )

    response.json({
      ok: true,
      data: rows,
    })
  } catch (error) {
    console.error('history load error:', error)
    response.status(500).json({
      ok: false,
      message: error instanceof Error ? error.message : '讀取歷史戰績失敗。',
    })
  }
})

app.delete('/api/history/:id', async (request, response) => {
  if (!pool) {
    response.status(500).json({
      ok: false,
      message: `DB 設定不完整，缺少：${missingEnv.join(', ')}`,
    })
    return
  }

  const id = Number(request.params.id)

  if (!Number.isInteger(id) || id <= 0) {
    response.status(400).json({
      ok: false,
      message: '戰績編號格式不正確。',
    })
    return
  }

  try {
    await ensureHistoryTable(pool, historyTableName)
    const [result] = await pool.execute(
      `DELETE FROM \`${historyTableName}\` WHERE id = ? LIMIT 1`,
      [id],
    )

    if (result.affectedRows === 0) {
      response.status(404).json({
        ok: false,
        message: '找不到要刪除的戰績。',
      })
      return
    }

    response.json({
      ok: true,
      message: '戰績已刪除。',
    })
  } catch (error) {
    console.error('history delete error:', error)
    response.status(500).json({
      ok: false,
      message: error instanceof Error ? error.message : '刪除戰績失敗。',
    })
  }
})

if (distReady) {
  app.use(express.static(distDir))

  app.get(/^(?!\/api).*/, (_request, response) => {
    response.sendFile(path.join(distDir, 'index.html'))
  })
}

app.listen(port, () => {
  console.log(`Server ready on http://localhost:${port}`)
  if (missingEnv.length > 0) {
    console.log(`Missing env: ${missingEnv.join(', ')}`)
  }
})

async function ensureMatchTable(poolInstance, currentTableName) {
  await poolInstance.execute(`
    CREATE TABLE IF NOT EXISTS \`${currentTableName}\` (
      time INT(11) NOT NULL,
      personnel TEXT NOT NULL,
      battlecombination TEXT DEFAULT NULL,
      PRIMARY KEY (time)
    ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  `)
}

async function ensureHistoryTable(poolInstance, currentTableName) {
  await poolInstance.execute(`
    CREATE TABLE IF NOT EXISTS \`${currentTableName}\` (
      id INT(11) NOT NULL AUTO_INCREMENT,
      time INT(11) NOT NULL COMMENT '記錄時間',
      dayOfWeek INT(1) NOT NULL COMMENT '星期',
      score VARCHAR(255) NOT NULL COMMENT '隊伍分數 [ [隊伍1分數], [隊伍2分數] ]',
      winScore INT(2) NOT NULL COMMENT '幾分獲勝',
      type INT(1) NOT NULL COMMENT '遊戲類型(0:雙打,1:單打)',
      players VARCHAR(255) NOT NULL COMMENT '玩家',
      team VARCHAR(255) NOT NULL COMMENT '玩家隊伍 [ [隊伍1成員], [隊伍2成員] ]',
      scoreList TEXT DEFAULT NULL COMMENT '得分過程[round, starter, winCount, winner]',
      PRIMARY KEY (id)
    ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  `)
}
