import {
  registerDecorator,
  ValidationArguments,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';
import { isValidPhoneNumber, parsePhoneNumberFromString } from 'libphonenumber-js';

/**
 * Country-aware phone validation. The value is expected as a full international
 * number (E.164, e.g. "+251911223344"), so the country is derived from the
 * value itself — no separate country field needed.
 */
@ValidatorConstraint({ name: 'IsValidPhone', async: false })
export class IsValidPhoneConstraint implements ValidatorConstraintInterface {
  validate(value: unknown): boolean {
    // Empty is allowed here; pair with @IsOptional / @IsNotEmpty as needed.
    if (value === undefined || value === null || value === '') return true;
    if (typeof value !== 'string') return false;
    return isValidPhoneNumber(value);
  }

  defaultMessage(args: ValidationArguments): string {
    return `${args.property} must be a valid international phone number (E.164, e.g. +251911223344)`;
  }
}

/** Class-validator decorator wrapping the country-aware phone constraint. */
export function IsValidPhone(validationOptions?: ValidationOptions) {
  return function (object: object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsValidPhoneConstraint,
    });
  };
}

/**
 * Normalize a phone string to canonical E.164. Returns the canonical form when
 * parseable, otherwise the trimmed original (tolerant — never throws), or the
 * value unchanged when empty/nullish.
 */
export function normalizeE164(
  value: string | null | undefined,
): string | null | undefined {
  if (value === undefined || value === null || value === '') return value;
  const parsed = parsePhoneNumberFromString(value);
  return parsed?.isValid() ? parsed.number : value.trim();
}
