import { Command } from 'commander';
import type { ApiClient } from '../api-client.js';

export interface PasswdPromptDeps {
  password(message: string): Promise<string>;
}

export interface PasswdCommandDeps {
  client: ApiClient;
  log: (...args: string[]) => void;
  prompt: PasswdPromptDeps;
}

interface Me {
  id: string;
  email: string;
}

interface UserView {
  id: string;
  email: string;
}

async function defaultPassword(message: string): Promise<string> {
  const { default: inquirer } = await import('inquirer');
  const { answer } = await inquirer.prompt([{ type: 'password', name: 'answer', message, mask: '*' }]);
  return answer as string;
}

function validateNew(newPassword: string, confirm: string): void {
  if (newPassword !== confirm) {
    throw new Error('Passwords do not match');
  }
  if (newPassword.length < 8) {
    throw new Error('Password must be at least 8 characters');
  }
}

export function createPasswdCommand(deps?: Partial<PasswdCommandDeps>): Command {
  const log = deps?.log ?? ((...args: string[]): void => { console.log(...args); });
  const prompt: PasswdPromptDeps = deps?.prompt ?? { password: defaultPassword };

  return new Command('passwd')
    .description('Change a user password (your own when called without an argument)')
    .argument('[user]', 'email or id of the user whose password to change (defaults to yourself)')
    .action(async (target: string | undefined) => {
      const client = deps?.client;
      if (!client) throw new Error('passwd: no API client configured');

      const me = await client.get<Me>('/api/v1/auth/me');
      const isSelf = target === undefined || target === me.email || target === me.id;

      if (isSelf) {
        // Self-service: prove identity with the current password, then set the new one.
        const currentPassword = await prompt.password('Current password');
        const newPassword = await prompt.password('New password');
        const confirm = await prompt.password('Retype new password');
        validateNew(newPassword, confirm);
        await client.post('/api/v1/users/me/password', { currentPassword, newPassword });
        log(`Password updated for ${me.email}.`);
        return;
      }

      // Admin reset of another user — requires edit:users.
      const targetUser = await client.get<UserView>(`/api/v1/users/${encodeURIComponent(target as string)}`);
      const newPassword = await prompt.password(`New password for ${targetUser.email}`);
      const confirm = await prompt.password('Retype new password');
      validateNew(newPassword, confirm);
      await client.put(`/api/v1/users/${targetUser.id}/password`, { newPassword });
      log(`Password reset for ${targetUser.email}.`);
    });
}
