// Authentication routes
import type { FastifyInstance } from "fastify";
import bcrypt from "bcrypt";
import { queryOne, execute } from "../db/client.js";
import { authenticate } from "../middleware/auth.js";
import type { User, RegisterInput, LoginInput, AuthResponse } from "../types/index.js";

const SALT_ROUNDS = 10;

export async function authRoutes(app: FastifyInstance): Promise<void> {
  // POST /api/auth/register
  app.post<{ Body: RegisterInput }>("/register", async (request, reply) => {
    const { username, password, nickname } = request.body;

    if (!username || !password) {
      return reply.status(400).send({
        error: "Bad Request",
        message: "Username and password are required",
        statusCode: 400,
      });
    }

    if (password.length < 6) {
      return reply.status(400).send({
        error: "Bad Request",
        message: "Password must be at least 6 characters",
        statusCode: 400,
      });
    }

    const existing = queryOne("SELECT id FROM users WHERE username = ?", [username]);
    if (existing) {
      return reply.status(409).send({
        error: "Conflict",
        message: "Username already exists",
        statusCode: 409,
      });
    }

    const id = crypto.randomUUID();
    const passwordHash = await bcrypt.hash(password, SALT_ROUNDS);
    const now = new Date().toISOString();

    execute(
      "INSERT INTO users (id, username, password_hash, nickname, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)",
      [id, username, passwordHash, nickname || username, now, now]
    );

    const user = queryOne<User>(
      "SELECT id, username, nickname, role, created_at, updated_at FROM users WHERE id = ?",
      [id]
    );
    if (!user) {
      return reply.status(500).send({ error: "Internal Error", message: "Failed to create user", statusCode: 500 });
    }

    const token = app.jwt.sign({ userId: id, username, role: user.role });

    return reply.status(201).send({ token, user } satisfies AuthResponse);
  });

  // POST /api/auth/login
  app.post<{ Body: LoginInput }>("/login", async (request, reply) => {
    const { username, password } = request.body;

    if (!username || !password) {
      return reply.status(400).send({
        error: "Bad Request",
        message: "Username and password are required",
        statusCode: 400,
      });
    }

    const user = queryOne<User & { password_hash: string }>(
      "SELECT * FROM users WHERE username = ?",
      [username]
    );

    if (!user) {
      return reply.status(401).send({
        error: "Unauthorized",
        message: "Invalid username or password",
        statusCode: 401,
      });
    }

    const valid = await bcrypt.compare(password, user.password_hash);
    if (!valid) {
      return reply.status(401).send({
        error: "Unauthorized",
        message: "Invalid username or password",
        statusCode: 401,
      });
    }

    const token = app.jwt.sign({ userId: user.id, username: user.username, role: user.role });

    const { password_hash, ...safeUser } = user;

    return { token, user: safeUser } satisfies AuthResponse;
  });

  // GET /api/auth/me — current user info
  app.get("/me", { onRequest: [authenticate] }, async (request, reply) => {
    const jwtUser = request.user as unknown as { userId: string };
    const user = queryOne<User>(
      "SELECT id, username, nickname, role, created_at, updated_at FROM users WHERE id = ?",
      [jwtUser.userId]
    );

    if (!user) {
      return reply.status(404).send({
        error: "Not Found",
        message: "User not found",
        statusCode: 404,
      });
    }

    return { data: user };
  });
}
