/**
 * Login with Email Use Case
 * 
 * Authenticates a user with email and password.
 */

import type { IUserRepository } from '../../domain/repositories/IUserRepository';
import type { AuthenticatedUserDTO } from '../dto/AuthenticatedUserDTO';
import type { AuthSessionDTO } from '../dto/AuthSessionDTO';
import type { IdentitySessionPort } from '../ports/IdentitySessionPort';

export interface LoginCommandDTO {
  email: string;
  password: string;
}

export class LoginWithEmailUseCase {
  constructor(
    private readonly userRepository: IUserRepository,
    private readonly sessionPort: IdentitySessionPort,
  ) {}

  async execute(command: LoginCommandDTO): Promise<AuthSessionDTO> {
    // Validate inputs
    if (!command.email || !command.password) {
      throw new Error('Email and password are required');
    }

    // Find user by email
    const user = await this.userRepository.findByEmail(command.email.toLowerCase().trim());
    if (!user) {
      throw new Error('Invalid email or password');
    }

    // Verify password
    const passwordHash = await this.hashPassword(command.password, user.salt);
    if (passwordHash !== user.passwordHash) {
      throw new Error('Invalid email or password');
    }

    // Create session
    const authenticatedUserBase: AuthenticatedUserDTO = {
      id: user.id,
      displayName: user.displayName,
      email: user.email,
    };

    const authenticatedUser: AuthenticatedUserDTO =
      user.primaryDriverId !== undefined
        ? { ...authenticatedUserBase, primaryDriverId: user.primaryDriverId }
        : authenticatedUserBase;

    return this.sessionPort.createSession(authenticatedUser);
  }

  private async hashPassword(password: string, salt: string): Promise<string> {
    // Simple hash for demo - in production, use bcrypt or argon2
    const data = password + salt;
    if (typeof crypto !== 'undefined' && crypto.subtle) {
      const encoder = new TextEncoder();
      const dataBuffer = encoder.encode(data);
      const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
      const hashArray = Array.from(new Uint8Array(hashBuffer));
      return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    }
    // Fallback for environments without crypto.subtle
    let hash = 0;
    for (let i = 0; i < data.length; i++) {
      const char = data.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash;
    }
    return Math.abs(hash).toString(16).padStart(16, '0');
  }
}