// server/db/index.ts
import { RoomPreviewInfo, Message} from "@/types";
import mysql from 'mysql2/promise';
import type { RowDataPacket } from 'mysql2';

// ------------------- Database Connection Setup -------------------

// Create a connection pool. Using a pool is more efficient than creating
// a new connection for every query.
const pool = mysql.createPool({
  host: process.env.DB_HOST || 'localhost',
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || 'password',
  database: process.env.DB_DATABASE || 'my_chat_app',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

// Test the connection
pool.getConnection()
  .then(connection => {
    console.log("Successfully connected to the MySQL database.");
    connection.release();
  })
  .catch(err => {
    console.error("Error connecting to the MySQL database:", err);
  });


// ------------------- Database Functions -------------------

// 添加房间
export const addRoom = async (roomName: string, user: string): Promise<number> => {
  try {
    const [result] = await pool.execute<mysql.ResultSetHeader>(
      'INSERT INTO rooms (roomName, creater) VALUES (?, ?)',
      [roomName, user]
    );
    console.log(`房间 '${roomName}' 添加成功，ID: ${result.insertId}`);
    return result.insertId;
  } catch (error) {
    console.error(`添加房间 '${roomName}' 失败:`, error);
    throw error;
  }
};

// 列出房间
export const listRoom = async (): Promise<RoomPreviewInfo[]> => {
  // This is a more advanced query to get each room and its LATEST message in one go.
  const query = `
    SELECT
        r.roomId,
        r.roomName,
        m.messageId,
        m.sender,
        m.content,
        m.time
    FROM rooms r
    LEFT JOIN messages m ON m.messageId = (
        SELECT MAX(messageId)
        FROM messages
        WHERE roomId = r.roomId
    )
    ORDER BY r.roomId DESC;
  `;
  const [rows] = await pool.query<mysql.RowDataPacket[]>(query);
  
  // Map the raw database rows to our desired RoomPreviewInfo structure
  console.log(rows)
  return rows.map(row => ({
    roomId: row.roomId,
    roomName: row.roomName,
    lastMessage: row.messageId ? { // If messageId is null, there are no messages
      messageId: row.messageId,
      roomId: row.roomId,
      sender: row.sender,
      content: row.content,
      time: Number(row.time) // `time` is BIGINT, convert it to number
    } : null
  }));
};

// 删除房间
export const deleteRoom = async (roomId: number, user: string): Promise<void> => {
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();

    // 1. 查找房间并验证创建者
    const [rows] = await connection.execute<mysql.RowDataPacket[]>(
      'SELECT creater FROM rooms WHERE roomId = ?',
      [roomId]
    );

    if (rows.length === 0) {
      throw new Error(`房间 ${roomId} 不存在`);
    }

    const room = rows[0];
    if (room.creater !== user) {
      throw new Error(`用户 ${user} 无权删除房间 ${roomId}`);
    }

    // 2. 删除房间 (messages will be deleted automatically due to ON DELETE CASCADE)
    await connection.execute('DELETE FROM rooms WHERE roomId = ?', [roomId]);

    await connection.commit();
    console.log(`房间 ${roomId} 删除成功`);
  } catch (error) {
    await connection.rollback();
    console.error(`删除房间 ${roomId} 失败:`, error);
    throw error;
  } finally {
    connection.release();
  }
};

// 获取房间消息列表
export const getRoomMessages = async (roomId: number): Promise<Message[]> => {
  // 1. 验证房间是否存在（使用RowDataPacket[]类型）
  const [roomRows] = await pool.execute<RowDataPacket[]>(
    'SELECT 1 FROM rooms WHERE roomId = ?',
    [roomId]
  );
  if (roomRows.length === 0) {
    throw new Error(`房间 ${roomId} 不存在`);
  }

  // 2. 获取房间消息（使用RowDataPacket[]类型）
  const [messageRows] = await pool.execute<RowDataPacket[]>(
    'SELECT * FROM messages WHERE roomId = ? ORDER BY messageId ASC',
    [roomId]
  );

  // 3. 转换为Message类型数组（处理time字段为数字）
  return messageRows.map((msg): Message => {
    // 断言msg包含Message的所有字段（除了time）
    const baseMsg = msg as Omit<Message, 'time'>;
    // 转换time字段为数字（假设数据库中time是字符串或日期对象）
    return {
      ...baseMsg,
      time: typeof msg.time === 'string' 
        ? parseInt(msg.time, 10) // 若为字符串（如"2025-08-28 16:00:00"），转换为时间戳（可选）
        : msg.time instanceof Date 
          ? msg.time.getTime() // 若为Date对象，转换为时间戳
          : Number(msg.time) // 其他情况，强制转换为数字
    };
  });
};

// 添加消息
export const addMessage = async (
  roomId: number, 
  content: string, 
  sender: string
): Promise<Message> => {
  // 1. 验证房间是否存在 (optional but good practice)
  const [roomRows] = await pool.execute<mysql.RowDataPacket[]>(
    'SELECT 1 FROM rooms WHERE roomId = ?',
    [roomId]
  );
  if (roomRows.length === 0) {
    throw new Error(`房间 ${roomId} 不存在`);
  }
  
  // 2. 创建消息
  const timestamp = Date.now();
  const [result] = await pool.execute<mysql.ResultSetHeader>(
    'INSERT INTO messages (roomId, sender, content, time) VALUES (?, ?, ?, ?)',
    [roomId, sender, content, timestamp]
  );
  
  const newMessage: Message = {
    messageId: result.insertId,
    roomId,
    sender,
    content,
    time: timestamp
  };

  console.log(`消息添加到房间 ${roomId} 成功`);
  return newMessage;
};

// 获取增量消息更新
export const getUpdatedMessages = async (
  roomId: number, 
  sinceMessageId: number
): Promise<Message[]> => {
  // 1. 查询数据库（使用RowDataPacket[]作为泛型参数，符合mysql2类型约束）
  const [rows] = await pool.execute<RowDataPacket[]>(
    'SELECT messageId, roomId, sender, content, time FROM messages WHERE roomId = ? AND messageId > ? ORDER BY messageId ASC',
    [roomId, sinceMessageId]
  );

  // 2. 转换RowDataPacket[]为Message[]（手动映射+类型安全）
  const messages: Message[] = rows.map((row) => {
    // 2.1 断言row包含messages表的所有字段（解决类型推断问题）
    const dbRow = row as RowDataPacket & {
      messageId: number;
      roomId: number;
      sender: string;
      content: string;
      time: string; // 数据库中time字段是DATETIME，存储为字符串（如"2025-08-28 16:00:00"）
    };

    // 2.2 手动映射每个字段到Message接口（确保无遗漏）
    return {
      messageId: dbRow.messageId,  // 直接取数据库字段（INT→number）
      roomId: dbRow.roomId,        // 直接取数据库字段（INT→number）
      sender: dbRow.sender,        // 直接取数据库字段（VARCHAR→string）
      content: dbRow.content,      // 直接取数据库字段（TEXT→string）
      time: new Date(dbRow.time).getTime(), // 关键：将DATETIME字符串转换为数字时间戳（毫秒）
    };
  });

  console.log(`在房间 ${roomId} 找到 ${messages.length} 条新消息 (since ID: ${sinceMessageId})`);
  return messages;
};

// 定义 User 类型，方便代码提示和类型检查
export interface User {
  userId: number;
  username: string;
  passwordHash: string; // 注意我们操作的是 passwordHash
  createdAt: Date;
}

/**
 * 根据用户名查找用户
 * @param username 用户名
 * @returns 返回用户对象（包含密码哈希）或 null
 */
export const findUserByUsername = async (username: string): Promise<User | null> => {
  try {
    const [rows] = await pool.execute<mysql.RowDataPacket[]>(
      'SELECT * FROM users WHERE username = ?',
      [username]
    );
    if (rows.length === 0) {
      return null; // 用户不存在
    }
    return rows[0] as User;
  } catch (error) {
    console.error(`Error finding user '${username}':`, error);
    throw error;
  }
};

/**
 * 创建新用户
 * @param username 用户名
 * @param passwordHash 已经哈希过的密码
 * @returns 返回新创建的用户对象（不含密码哈希）
 */
export const createUser = async (username: string, passwordHash: string): Promise<Omit<User, 'passwordHash'>> => {
  try {
    const [result] = await pool.execute<mysql.ResultSetHeader>(
      'INSERT INTO users (username, passwordHash) VALUES (?, ?)',
      [username, passwordHash]
    );
    console.log(`User '${username}' created successfully with ID: ${result.insertId}`);
    return {
      userId: result.insertId,
      username: username,
      createdAt: new Date() // 返回当前时间作为创建时间
    };
  } catch (error) {
    console.error(`Error creating user '${username}':`, error);
    // 检查是否是唯一键冲突错误
    if (error instanceof Error && 'code' in error && error.code === 'ER_DUP_ENTRY') {
        throw new Error(`Username '${username}' already exists.`);
    }
    throw error;
  }
};