// src/server/features/auth/auth.service.ts
// Business logic for authentication (hashing, JWT generation)

import { db } from '../../shared/db/client';
import { employees } from '../../shared/db/schema';
import { eq } from 'drizzle-orm';
import { logger } from '../../shared/lib/logger';
import { AppError, ErrorCode } from '../../shared/lib/errors';
import * as argon2 from 'argon2';
import { randomUUID } from 'node:crypto';

// Types
export interface LoginInput {
  username: string;
  password: string;
}

export interface RegisterInput {
  username: string;
  password: string;
  email: string;
  name: string;
  position?: string;
  phone?: string;
}

export interface AuthResult {
  user: {
    id: string;
    username: string;
    email: string | null;
    role: string;
  };
}

export interface UserResult {
  id: string;
  username: string;
  email: string | null;
  role: string;
}

// Password hashing using argon2 (secure and modern)
export async function hashPassword(password: string): Promise<string> {
  return await argon2.hash(password, {
    type: argon2.argon2id,
    memoryCost: 65536, // 64 MB
    timeCost: 3,
    parallelism: 4,
  });
}

// Password verification using argon2
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
  try {
    return await argon2.verify(hash, password);
  } catch (error) {
    logger.error('Password verification error:', error);
    return false;
  }
}

// Login function
export async function login(input: LoginInput): Promise<AuthResult> {
  const { username, password } = input;

  // Find employee by username
  const employeeResult = await db
    .select({
      id: employees.id,
      username: employees.username,
      passwordHash: employees.passwordHash,
      email: employees.email,
      role: employees.role,
    })
    .from(employees)
    .where(eq(employees.username, username))
    .limit(1);

  if (!employeeResult || employeeResult.length === 0) {
    logger.warn(`Login attempt failed: User not found - ${username}`);
    const error = new AppError('Неверный логин или пароль', 401, ErrorCode.UNAUTHORIZED);
    logger.error(`Throwing AppError: ${error.message}, statusCode: ${error.statusCode}, code: ${error.code}`);
    throw error;
  }

  const employee = employeeResult[0];

  // Verify password
  if (!employee.passwordHash) {
    logger.warn(`Login attempt failed: User has no password hash - ${username}`);
    const error = new AppError('Неверный логин или пароль', 401, ErrorCode.UNAUTHORIZED);
    logger.error(`Throwing AppError: ${error.message}, statusCode: ${error.statusCode}, code: ${error.code}`);
    throw error;
  }

  const isValidPassword = await verifyPassword(password, employee.passwordHash);
  if (!isValidPassword) {
    logger.warn(`Login attempt failed: Invalid password - ${username}`);
    const error = new AppError('Неверный логин или пароль', 401, ErrorCode.UNAUTHORIZED);
    logger.error(`Throwing AppError: ${error.message}, statusCode: ${error.statusCode}, code: ${error.code}`);
    throw error;
  }

  logger.info(`User logged in successfully: ${username}`);

  return {
    user: {
      id: employee.id,
      username: employee.username!,
      email: employee.email,
      role: employee.role!,
    },
  };
}

// Register function
export async function register(input: RegisterInput): Promise<UserResult> {
  const { username, password, email, name, position = 'Staff', phone } = input;

  // Check if username already exists
  const existingEmployee = await db
    .select({ id: employees.id })
    .from(employees)
    .where(eq(employees.username, username))
    .limit(1);

  if (existingEmployee && existingEmployee.length > 0) {
    logger.warn(`Registration attempt failed: Username already exists - ${username}`);
    throw new AppError('Пользователь с таким именем уже существует', 409, ErrorCode.CONFLICT);
  }

  // Hash password
  const passwordHash = await hashPassword(password);

  // Generate ID
  const employeeId = randomUUID();
  const now = new Date();

  // Create employee record in unified table
  await db.insert(employees).values({
    id: employeeId,
    fullName: name,
    position,
    phone: phone || '',
    email,
    username,
    passwordHash,
    role: 'MANAGER',
    createdAt: now,
    updatedAt: now,
  });

  // Fetch complete employee record
  const employeeResult = await db
    .select({
      id: employees.id,
      username: employees.username,
      email: employees.email,
      role: employees.role,
    })
    .from(employees)
    .where(eq(employees.id, employeeId))
    .limit(1);

  const employee = employeeResult[0];

  logger.info(`New user registered: ${username}`);

  return {
    id: employee.id,
    username: employee.username!,
    email: employee.email,
    role: employee.role!,
  };
}
