import { eq } from 'drizzle-orm';
import { db } from '../config/database.js';
import { users } from '../db/schema.js';
import { hashPassword, comparePassword } from '../utils/password.js';
import { generateTokenPair } from '../utils/jwt.js';
import * as emailAccountService from './email-account.service.js';
import {
  AuthenticationError,
  NotFoundError,
} from '../utils/errors.js';
import { logLoginAttempt, logLogin, logLogout, logPasswordChange, logEmailLink } from './audit.service.js';

/**
 * KROK 1: Login s temporary password
 */
export const loginWithTempPassword = async (username, password, ipAddress, userAgent) => {
  try {
    // Najdi usera
    const [user] = await db
      .select()
      .from(users)
      .where(eq(users.username, username))
      .limit(1);

    if (!user) {
      throw new AuthenticationError('Nesprávne prihlasovacie údaje');
    }

    // Ak už user zmenil heslo, použije sa permanentné heslo
    if (user.changedPassword && user.password) {
      const isValid = await comparePassword(password, user.password);
      if (!isValid) {
        throw new AuthenticationError('Nesprávne prihlasovacie údaje');
      }
    } else {
      // Ak ešte nezmenil heslo, použije sa temporary password
      if (!user.tempPassword) {
        throw new AuthenticationError('Účet nie je správne nastavený');
      }

      // Temporary password môže byť plain text alebo hash (závisí od seeding)
      // Pre bezpečnosť ho budeme hashovať pri vytvorení
      const isValid = await comparePassword(password, user.tempPassword);
      if (!isValid) {
        throw new AuthenticationError('Nesprávne prihlasovacie údaje');
      }
    }

    // Update last login
    await db
      .update(users)
      .set({ lastLogin: new Date() })
      .where(eq(users.id, user.id));

    // Generuj JWT tokeny
    const tokens = generateTokenPair(user);

    // Check if user has email accounts (many-to-many)
    const userEmailAccounts = await emailAccountService.getUserEmailAccounts(user.id);

    // Log successful login
    await logLoginAttempt(username, true, ipAddress, userAgent);
    await logLogin(user.id, username, ipAddress, userAgent);

    return {
      user: {
        id: user.id,
        username: user.username,
        firstName: user.firstName,
        lastName: user.lastName,
        role: user.role,
        changedPassword: user.changedPassword,
      },
      tokens,
      needsPasswordChange: !user.changedPassword,
      needsEmailSetup: userEmailAccounts.length === 0,
    };
  } catch (error) {
    // Log failed login attempt
    await logLoginAttempt(username, false, ipAddress, userAgent, error.message);
    throw error;
  }
};

/**
 * KROK 2: Nastavenie nového hesla
 */
export const setNewPassword = async (userId, newPassword, 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ý');
  }

  // Allow users to change password anytime (removed restriction)
  // if (user.changedPassword) {
  //   throw new ValidationError('Heslo už bolo zmenené');
  // }

  // Hash nového hesla
  const hashedPassword = await hashPassword(newPassword);

  // Update user
  await db
    .update(users)
    .set({
      password: hashedPassword,
      changedPassword: true,
      tempPassword: null, // Vymaž temporary password
      updatedAt: new Date(),
    })
    .where(eq(users.id, userId));

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

  return {
    success: true,
    message: 'Heslo úspešne nastavené',
  };
};

/**
 * KROK 3: Pripojenie emailu s JMAP validáciou
 * Používa many-to-many vzťah cez userEmailAccounts
 */
export const linkEmail = async (userId, email, emailPassword, 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ý');
  }

  // Použij emailAccountService ktorý automaticky vytvorí many-to-many link
  const newEmailAccount = await emailAccountService.createEmailAccount(
    userId,
    email,
    emailPassword
  );

  if (auditContext) {
    await logEmailLink(auditContext.userId, email, auditContext.ipAddress, auditContext.userAgent);
  }

  return {
    success: true,
    accountId: newEmailAccount.jmapAccountId,
    emailAccountId: newEmailAccount.id,
    isPrimary: newEmailAccount.isPrimary,
    shared: newEmailAccount.shared,
    message: newEmailAccount.shared
      ? 'Email účet už existoval a bol zdieľaný s vami'
      : 'Nový email účet úspešne vytvorený a pripojený',
  };
};

/**
 * Skip email setup
 */
export const skipEmailSetup = 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ý');
  }

  return {
    success: true,
    message: 'Email setup preskočený',
  };
};

/**
 * Logout - clear tokens (handled on client side)
 */
export const logout = async (auditContext = null) => {
  if (auditContext) {
    await logLogout(auditContext.userId, auditContext.ipAddress, auditContext.userAgent);
  }

  return {
    success: true,
    message: 'Úspešne odhlásený',
  };
};

/**
 * Get user by ID
 * Email credentials sú v emailAccounts tabuľke (many-to-many)
 */
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,
    })
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

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

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

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