import { db } from '../config/database.js';
import { users, userEmailAccounts, emailAccounts } from '../db/schema.js';
import { eq, count } from 'drizzle-orm';
import { hashPassword, generateTempPassword } from '../utils/password.js';
import { ConflictError, NotFoundError } from '../utils/errors.js';
import * as emailAccountService from './email-account.service.js';
import { logger } from '../utils/logger.js';
import { logUserCreation, logRoleChange, logUserDeleted } from './audit.service.js';

/**
 * Skontroluj či username už neexistuje
 */
export const checkUsernameExists = async (username) => {
  const [existingUser] = await db
    .select()
    .from(users)
    .where(eq(users.username, username))
    .limit(1);

  return !!existingUser;
};

/**
 * Vytvorenie nového usera s automatic temporary password
 */
export const createUser = async (username, firstName, lastName, role, email, emailPassword, auditContext = null) => {
  // Skontroluj či username už neexistuje
  if (await checkUsernameExists(username)) {
    throw new ConflictError('Username už existuje');
  }

  // Automaticky vygeneruj temporary password
  const tempPassword = generateTempPassword(12);
  const hashedTempPassword = await hashPassword(tempPassword);

  // Validuj role - 'admin', 'team_leader' alebo 'member'
  const validRoles = ['admin', 'team_leader', 'member'];
  const validRole = validRoles.includes(role) ? role : 'member';

  // Vytvor usera
  const [newUser] = await db
    .insert(users)
    .values({
      username,
      tempPassword: hashedTempPassword,
      role: validRole,
      firstName: firstName || null,
      lastName: lastName || null,
      changedPassword: false,
    })
    .returning();

  // Ak sú poskytnuté email credentials, vytvor email account (many-to-many)
  let emailAccountCreated = false;
  let emailAccountData = null;

  if (email && emailPassword) {
    try {
      const newEmailAccount = await emailAccountService.createEmailAccount(
        newUser.id,
        email,
        emailPassword
      );

      emailAccountCreated = true;
      emailAccountData = {
        id: newEmailAccount.id,
        email: newEmailAccount.email,
        jmapAccountId: newEmailAccount.jmapAccountId,
        shared: newEmailAccount.shared,
      };
    } catch (emailError) {
      logger.error('Nepodarilo sa vytvoriť email účet:', { error: emailError.message });
    }
  }

  if (auditContext) {
    await logUserCreation(auditContext.userId, newUser.id, username, newUser.role, auditContext.ipAddress, auditContext.userAgent);
  }

  return {
    user: newUser,
    tempPassword,
    emailAccountCreated,
    emailAccountData,
  };
};

/**
 * Zoznam všetkých userov
 */
export const getAllUsers = async () => {
  const allUsers = await db
    .select({
      id: users.id,
      username: users.username,
      firstName: users.firstName,
      lastName: users.lastName,
      role: users.role,
      changedPassword: users.changedPassword,
      lastLogin: users.lastLogin,
      createdAt: users.createdAt,
    })
    .from(users);

  return allUsers;
};

/**
 * Získanie konkrétneho usera
 */
export const getUserById = async (userId) => {
  const [user] = await db
    .select({
      id: users.id,
      username: users.username,
      firstName: users.firstName,
      lastName: users.lastName,
      role: users.role,
      changedPassword: users.changedPassword,
      lastLogin: users.lastLogin,
      createdAt: users.createdAt,
      updatedAt: users.updatedAt,
    })
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  if (!user) {
    throw new NotFoundError('Používateľ nenájdený');
  }

  // Get user's email accounts (cez many-to-many)
  const userEmailAccountsList = await emailAccountService.getUserEmailAccounts(userId);

  return {
    ...user,
    emailAccounts: userEmailAccountsList,
  };
};

/**
 * Zmena role usera
 */
export const changeUserRole = async (userId, newRole, auditContext = null) => {
  // Získaj starú rolu
  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  if (!user) {
    throw new NotFoundError('Používateľ nenájdený');
  }

  const oldRole = user.role;

  // Update role
  await db
    .update(users)
    .set({
      role: newRole,
      updatedAt: new Date(),
    })
    .where(eq(users.id, userId));

  if (auditContext) {
    await logRoleChange(auditContext.userId, userId, oldRole, newRole, auditContext.ipAddress, auditContext.userAgent);
  }

  return { userId, oldRole, newRole };
};

/**
 * Update user details (firstName, lastName)
 */
export const updateUser = async (userId, data) => {
  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  if (!user) {
    throw new NotFoundError('Používateľ nenájdený');
  }

  const { firstName, lastName } = data;

  const [updated] = await db
    .update(users)
    .set({
      firstName: firstName !== undefined ? firstName : user.firstName,
      lastName: lastName !== undefined ? lastName : user.lastName,
      updatedAt: new Date(),
    })
    .where(eq(users.id, userId))
    .returning({
      id: users.id,
      username: users.username,
      firstName: users.firstName,
      lastName: users.lastName,
      role: users.role,
      changedPassword: users.changedPassword,
      lastLogin: users.lastLogin,
      createdAt: users.createdAt,
    });

  return updated;
};

/**
 * Reset user password (generate new temp password)
 */
export const resetUserPassword = async (userId) => {
  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  if (!user) {
    throw new NotFoundError('Používateľ nenájdený');
  }

  const tempPassword = generateTempPassword(12);
  const hashedTempPassword = await hashPassword(tempPassword);

  await db
    .update(users)
    .set({
      tempPassword: hashedTempPassword,
      password: null,
      changedPassword: false,
      updatedAt: new Date(),
    })
    .where(eq(users.id, userId));

  return { userId, tempPassword };
};

/**
 * Zmazanie usera
 */
export const deleteUser = async (userId, auditContext = null) => {
  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  if (!user) {
    throw new NotFoundError('Používateľ nenájdený');
  }

  // Zabraň zmazaniu posledného admina
  if (user.role === 'admin') {
    const [adminCount] = await db
      .select({ count: count() })
      .from(users)
      .where(eq(users.role, 'admin'));

    if ((adminCount?.count || 0) <= 1) {
      throw new ConflictError('Nemôžete zmazať posledného administrátora');
    }
  }

  // Get user's email account IDs before deletion
  const userEmailAccountLinks = await db
    .select({ emailAccountId: userEmailAccounts.emailAccountId })
    .from(userEmailAccounts)
    .where(eq(userEmailAccounts.userId, userId));

  const emailAccountIds = userEmailAccountLinks.map(link => link.emailAccountId);

  // Save username before deletion for audit
  const deletedUsername = user.username;

  // Delete user (cascades userEmailAccounts links)
  await db.delete(users).where(eq(users.id, userId));

  // Delete orphaned email accounts (no users linked)
  let deletedEmailAccounts = 0;
  for (const emailAccountId of emailAccountIds) {
    const [remainingLinks] = await db
      .select({ count: count() })
      .from(userEmailAccounts)
      .where(eq(userEmailAccounts.emailAccountId, emailAccountId));

    if ((remainingLinks?.count || 0) === 0) {
      await db.delete(emailAccounts).where(eq(emailAccounts.id, emailAccountId));
      deletedEmailAccounts++;
    }
  }

  if (auditContext) {
    await logUserDeleted(auditContext.userId, userId, deletedUsername, auditContext.ipAddress, auditContext.userAgent);
  }

  return { deletedEmailAccounts };
};
