import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

import { v4 as uuidv4 } from 'uuid';
import { db } from '../application/database';
import { ResponseError } from '../error/response-error';
import { LoginUserRequest, RegisterUserRequest, User, UserResponse, toUserResponse } from '../model/user-model';
import { Validation } from '../validation/validation';
import { AuthValidation } from '../validation/auth-validation';

export class AuthService {
  static async register(request: RegisterUserRequest): Promise<UserResponse> {
    // Validate the registration request
    const registerRequest = Validation.validate(AuthValidation.REGISTER, request);

    // Check if the email already exists
    const existingUser = await db.queryOne<{ id: string }>('SELECT id FROM user WHERE email = ? LIMIT 1', [
      registerRequest.email,
    ]);

    if (existingUser) {
      throw new ResponseError(400, 'Email sudah terdaftar');
    }

    // Hash the password before storing it
    const hashedPassword = await bcrypt.hash(registerRequest.password, 10);

    // Generate a new UUID for the user ID
    const userId = uuidv4();

    // Insert the new user into the database
    await db.query('INSERT INTO user (id, full_name, email, whatsapp_number, password) VALUES (?, ?, ?, ?, ?)', [
      userId,
      registerRequest.full_name,
      registerRequest.email,
      registerRequest.whatsapp_number,
      hashedPassword,
    ]);

    // Retrieve the newly created user by the email
    const user = await db.queryOne<User>('SELECT * FROM user WHERE id = ? LIMIT 1', [userId]);

    if (!user) {
      throw new ResponseError(500, 'Gagal melakukan registrasi user');
    }

    return toUserResponse(user);
  }

  static async login(request: LoginUserRequest): Promise<UserResponse> {
    // Validate the login request
    const loginRequest = Validation.validate(AuthValidation.LOGIN, request);

    // Find the user by email
    const user = await db.queryOne<User>('SELECT * FROM user WHERE email = ? LIMIT 1', [loginRequest.email]);

    if (!user) {
      throw new ResponseError(400, 'Email atau password salah');
    }

    // Compare the password
    const passwordMatch = await bcrypt.compare(loginRequest.password, user.password);

    if (!passwordMatch) {
      throw new ResponseError(400, 'Email atau password salah');
    }

    // Generate a JWT token
    const token = jwt.sign(
      {
        id: user.id,
        email: user.email,
        full_name: user.full_name,
        whatsapp_number: user.whatsapp_number,
        role: user.role,
      },
      String(process.env.JWT_SECRET),
      {
        expiresIn: '24h',
      }
    );

    // Format the user response
    const response = toUserResponse(user);
    response.token = token;
    return response;
  }
}
