import dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';
import mysql from 'mysql2/promise';
import bcrypt from 'bcryptjs';
import argon2 from 'argon2';

dotenv.config();

const app = express();
const port = 3010;

app.use(
  cors({
    origin(origin, callback) {
      if (!origin) {
        callback(null, true);
        return;
      }
      callback(null, true);
    }
  })
);
app.use(express.json());

const pool = mysql.createPool({
  host: process.env.DB_HOST || 'nw.sgcode.cn',
  port: Number(process.env.DB_PORT || 21434),
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || 'root',
  database: process.env.DB_NAME || 'opencoze',
  waitForConnections: true,
  connectionLimit: 10
});

async function ensureUsersTable() {
  await pool.query(`
    CREATE TABLE IF NOT EXISTS \`user\` (
      id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
      name VARCHAR(128) NOT NULL DEFAULT '',
      unique_name VARCHAR(128) NOT NULL UNIQUE,
      email VARCHAR(128) NOT NULL UNIQUE,
      password VARCHAR(128) NOT NULL DEFAULT '',
      description VARCHAR(512) NOT NULL DEFAULT '',
      icon_uri VARCHAR(512) NOT NULL DEFAULT '',
      user_verified TINYINT(1) NOT NULL DEFAULT 0,
      locale VARCHAR(128) NOT NULL DEFAULT '',
      session_key VARCHAR(256) NOT NULL DEFAULT '',
      created_at BIGINT UNSIGNED NOT NULL DEFAULT 0,
      updated_at BIGINT UNSIGNED NOT NULL DEFAULT 0,
      deleted_at BIGINT UNSIGNED NULL DEFAULT NULL,
      PRIMARY KEY (id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  `);
}

app.get('/api/health', async (_req, res) => {
  try {
    await pool.query('SELECT 1');
    res.json({ ok: true });
  } catch (error) {
    console.error('Health check failed:', error);
    res.status(500).json({ ok: false, message: 'Database connection failed' });
  }
});

app.post('/api/register', async (req, res) => {
  try {
    const { email, password, confirmPassword } = req.body ?? {};

    if (!email || !password || !confirmPassword) {
      res.status(400).json({ message: 'Email, password, and confirm password are required' });
      return;
    }

    if (password !== confirmPassword) {
      res.status(400).json({ message: 'Passwords do not match' });
      return;
    }

    const trimmedEmail = String(email).trim().toLowerCase();
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(trimmedEmail)) {
      res.status(400).json({ message: 'Please enter a valid email address' });
      return;
    }

    if (String(password).length < 6) {
      res.status(400).json({ message: 'Password must be at least 6 characters' });
      return;
    }

    const [existingRows] = await pool.query('SELECT id FROM `user` WHERE email = ? LIMIT 1', [trimmedEmail]);
    if (existingRows.length > 0) {
      res.status(409).json({ message: 'Email is already registered' });
      return;
    }

    const passwordHash = await bcrypt.hash(String(password), 10);
    const uniqueName = trimmedEmail;
    const displayName = trimmedEmail.split('@')[0];
    const now = Date.now();
    await pool.query(
      'INSERT INTO `user` (name, unique_name, email, password, description, icon_uri, user_verified, locale, session_key, created_at, updated_at, deleted_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
      [displayName, uniqueName, trimmedEmail, passwordHash, '', '', 0, 'zh-CN', '', now, now, null]
    );

    res.status(201).json({ message: 'Registered successfully' });
  } catch (error) {
    console.error('Register failed:', error);
    res.status(500).json({ message: 'Register failed' });
  }
});

app.post('/api/login', async (req, res) => {
  try {
    const { email, password } = req.body ?? {};
    if (!email || !password) {
      res.status(400).json({ message: 'Email and password are required' });
      return;
    }

    const trimmedEmail = String(email).trim().toLowerCase();
    const [rows] = await pool.query('SELECT id, email, password FROM `user` WHERE email = ? LIMIT 1', [trimmedEmail]);
    const user = rows[0];

    if (!user) {
      res.status(401).json({ message: 'Invalid email or password' });
      return;
    }

    const rawPassword = String(password);
    const storedPassword = String(user.password || '');
    let isPasswordValid = false;

    if (storedPassword.startsWith('$argon2')) {
      isPasswordValid = await argon2.verify(storedPassword, rawPassword);
    } else if (storedPassword.startsWith('$2')) {
      isPasswordValid = await bcrypt.compare(rawPassword, storedPassword);
    }
    if (!isPasswordValid) {
      res.status(401).json({ message: 'Invalid email or password' });
      return;
    }

    res.json({
      message: 'Login successful',
      user: {
        id: user.id,
        email: user.email
      }
    });
  } catch (error) {
    console.error('Login failed:', error);
    res.status(500).json({ message: 'Login failed' });
  }
});

ensureUsersTable()
  .then(() => {
    app.listen(port, () => {
      console.log(`Auth API running at http://localhost:${port}`);
    });
  })
  .catch((error) => {
    console.error('Failed to initialize database:', error);
    process.exit(1);
  });
