/**
 * Input masking utilities for the Input component
 * These functions handle formatting and validation for specialized input types
 */
/**
 * Format credit card input with hyphens every 4 digits
 * @param value The raw input value
 * @returns The formatted credit card number
 */
const formatCreditCard = (value) => {
    // Remove all non-digit characters
    const digitsOnly = value.replace(/\D/g, '');
    // Add hyphen after every 4 digits
    const formatted = digitsOnly.replace(/(\d{4})(?=\d)/g, '$1-');
    // Limit to 16 digits + hyphens (19 chars total)
    return formatted.slice(0, 19);
};
/**
 * Format expiry date input as MM/YY
 * @param value The raw input value
 * @returns The formatted expiry date
 */
const formatExpiryDate = (value) => {
    // Remove all non-digit characters
    const digitsOnly = value.replace(/\D/g, '');
    // Format based on length
    if (digitsOnly.length <= 2) {
        return digitsOnly;
    }
    // Add slash after month
    return `${digitsOnly.slice(0, 2)}/${digitsOnly.slice(2, 4)}`;
};
/**
 * Validate month (01-12) in expiry date
 * @param value The current input value
 * @returns Whether the month is valid
 */
const isValidMonth = (value) => {
    // Extract month portion
    const month = parseInt(value.slice(0, 2), 10);
    // Check if it's a valid month (1-12)
    return month >= 1 && month <= 12;
};
/**
 * Apply phone number formatting (US format: (XXX) XXX-XXXX)
 * @param value The raw input value
 * @returns The formatted phone number
 */
const formatPhoneNumber = (value) => {
    // Remove all non-digit characters
    const digitsOnly = value.replace(/\D/g, '');
    // Format based on length
    if (digitsOnly.length <= 3) {
        return `(${digitsOnly}`;
    }
    else if (digitsOnly.length <= 6) {
        return `(${digitsOnly.slice(0, 3)}) ${digitsOnly.slice(3)}`;
    }
    else {
        return `(${digitsOnly.slice(0, 3)}) ${digitsOnly.slice(3, 6)}-${digitsOnly.slice(6, 10)}`;
    }
};
/**
 * Format US Social Security Number (XXX-XX-XXXX)
 * @param value The raw input value
 * @returns The formatted SSN
 */
const formatSSN = (value) => {
    // Remove all non-digit characters
    const digitsOnly = value.replace(/\D/g, '');
    // Format based on length
    if (digitsOnly.length <= 3) {
        return digitsOnly;
    }
    else if (digitsOnly.length <= 5) {
        return `${digitsOnly.slice(0, 3)}-${digitsOnly.slice(3)}`;
    }
    else {
        return `${digitsOnly.slice(0, 3)}-${digitsOnly.slice(3, 5)}-${digitsOnly.slice(5, 9)}`;
    }
};
/**
 * Format date input as MM/DD/YYYY, DD/MM/YYYY, or YYYY/MM/DD
 * WITH REAL-TIME VALIDATION - prevents invalid month/day values as user types
 * @param value The raw input value
 * @param format The date format to use (default: MM/DD/YYYY)
 * @returns The formatted date string (only valid digits are kept)
 */
const formatDateInput = (value, format = 'MM/DD/YYYY') => {
    // Remove all non-digit characters
    const digitsOnly = value.replace(/\D/g, '');
    // Format based on length and format type
    if (format === 'YYYY/MM/DD') {
        // Year first: YYYY/MM/DD
        // Year validation: 1900-2099 (but allow typing any 4 digits for UX)
        if (digitsOnly.length < 4) {
            return digitsOnly;
        }
        if (digitsOnly.length === 4) {
            return `${digitsOnly}/`;
        }
        // Month validation (01-12)
        if (digitsOnly.length === 5) {
            const monthDigit = parseInt(digitsOnly[4], 10);
            if (monthDigit > 1)
                return digitsOnly.slice(0, 4); // First digit of month can't be > 1
            return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4)}`;
        }
        if (digitsOnly.length === 6) {
            const month = parseInt(digitsOnly.slice(4, 6), 10);
            if (month < 1 || month > 12)
                return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4, 5)}`; // Invalid month
            return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4)}/`;
        }
        // Day validation (01-31)
        if (digitsOnly.length === 7) {
            parseInt(digitsOnly.slice(4, 6), 10);
            const dayDigit = parseInt(digitsOnly[6], 10);
            if (dayDigit > 3)
                return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4, 6)}/`; // First digit of day can't be > 3
            return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4, 6)}/${digitsOnly.slice(6)}`;
        }
        if (digitsOnly.length >= 8) {
            parseInt(digitsOnly.slice(4, 6), 10);
            const day = parseInt(digitsOnly.slice(6, 8), 10);
            if (day < 1 || day > 31)
                return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4, 6)}/${digitsOnly.slice(6, 7)}`; // Invalid day
            return `${digitsOnly.slice(0, 4)}/${digitsOnly.slice(4, 6)}/${digitsOnly.slice(6, 8)}`;
        }
        return digitsOnly;
    }
    else {
        // Month/Day first: MM/DD/YYYY or DD/MM/YYYY
        if (digitsOnly.length === 0)
            return '';
        // First part validation (month or day)
        if (digitsOnly.length === 1) {
            const firstDigit = parseInt(digitsOnly[0], 10);
            // First digit of month can't be > 1, first digit of day can't be > 3
            const maxFirstDigit = format === 'MM/DD/YYYY' ? 1 : 3;
            if (firstDigit > maxFirstDigit)
                return ''; // Reject invalid first digit
            return digitsOnly;
        }
        if (digitsOnly.length === 2) {
            const firstPart = parseInt(digitsOnly.slice(0, 2), 10);
            if (format === 'MM/DD/YYYY') {
                // Validate month (01-12)
                if (firstPart < 1 || firstPart > 12)
                    return digitsOnly.slice(0, 1); // Reject 2nd digit
            }
            else {
                // Validate day (01-31)
                if (firstPart < 1 || firstPart > 31)
                    return digitsOnly.slice(0, 1); // Reject 2nd digit
            }
            return `${digitsOnly}/`;
        }
        // Second part validation (day or month)
        if (digitsOnly.length === 3) {
            parseInt(digitsOnly.slice(0, 2), 10);
            const secondDigit = parseInt(digitsOnly[2], 10);
            // Second part: if MM/DD, second is day (max first digit 3); if DD/MM, second is month (max first digit 1)
            const maxSecondDigit = format === 'MM/DD/YYYY' ? 3 : 1;
            if (secondDigit > maxSecondDigit)
                return `${digitsOnly.slice(0, 2)}/`; // Reject invalid digit
            return `${digitsOnly.slice(0, 2)}/${digitsOnly.slice(2)}`;
        }
        if (digitsOnly.length === 4) {
            parseInt(digitsOnly.slice(0, 2), 10);
            const secondPart = parseInt(digitsOnly.slice(2, 4), 10);
            if (format === 'MM/DD/YYYY') {
                // Second part is day (01-31)
                if (secondPart < 1 || secondPart > 31)
                    return `${digitsOnly.slice(0, 2)}/${digitsOnly.slice(2, 3)}`; // Reject 4th digit
            }
            else {
                // Second part is month (01-12)
                if (secondPart < 1 || secondPart > 12)
                    return `${digitsOnly.slice(0, 2)}/${digitsOnly.slice(2, 3)}`; // Reject 4th digit
            }
            return `${digitsOnly.slice(0, 2)}/${digitsOnly.slice(2)}/`;
        }
        // Year part (no validation needed during typing)
        if (digitsOnly.length >= 5) {
            const firstPart = digitsOnly.slice(0, 2);
            const secondPart = digitsOnly.slice(2, 4);
            const yearPart = digitsOnly.slice(4, 8);
            return `${firstPart}/${secondPart}/${yearPart}`;
        }
        return digitsOnly;
    }
};
/**
 * Validate if a date string is a valid date
 * @param value The formatted date string
 * @param format The date format being used
 * @returns Whether the date is valid
 */
const isValidDateInput = (value, format = 'MM/DD/YYYY') => {
    const parts = value.split('/');
    if (parts.length !== 3)
        return false;
    let month, day, year;
    switch (format) {
        case 'MM/DD/YYYY':
            month = parseInt(parts[0], 10);
            day = parseInt(parts[1], 10);
            year = parseInt(parts[2], 10);
            break;
        case 'DD/MM/YYYY':
            day = parseInt(parts[0], 10);
            month = parseInt(parts[1], 10);
            year = parseInt(parts[2], 10);
            break;
        case 'YYYY/MM/DD':
            year = parseInt(parts[0], 10);
            month = parseInt(parts[1], 10);
            day = parseInt(parts[2], 10);
            break;
        default:
            return false;
    }
    if (isNaN(month) || isNaN(day) || isNaN(year))
        return false;
    if (month < 1 || month > 12)
        return false;
    if (day < 1 || day > 31)
        return false;
    if (year < 1900 || year > 2099)
        return false;
    // Check if day is valid for the month
    const date = new Date(year, month - 1, day);
    return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
};
/**
 * Format currency input (adds commas for thousands and limits decimal places)
 * @param value The raw input value
 * @param decimalPlaces Number of decimal places (default: 2)
 * @returns The formatted currency value
 */
const formatCurrency = (value, decimalPlaces = 2) => {
    // Handle special case of just a decimal point
    if (value === '.') {
        return '0.';
    }
    // Remove all characters except digits and decimal point
    const sanitized = value.replace(/[^\d.]/g, '');
    // Ensure only one decimal point
    const parts = sanitized.split('.');
    const integerPart = parts[0];
    const decimalPart = parts.length > 1 ? parts[1] : '';
    // Format integer part with commas
    const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    // Add decimal part if decimal point was present (even if empty)
    if (parts.length > 1) {
        return `${formattedInteger}.${decimalPart.slice(0, decimalPlaces)}`;
    }
    return formattedInteger;
};
/**
 * Apply specific input masking based on input type
 * @param value The current input value
 * @param type The type of mask to apply
 * @param options Additional options for formatting
 * @returns The masked/formatted value
 */
const applyInputMask = (value, type, options) => {
    switch (type) {
        case 'creditCard':
            return formatCreditCard(value);
        case 'expiryDate':
            return formatExpiryDate(value);
        case 'phone':
            return formatPhoneNumber(value);
        case 'ssn':
            return formatSSN(value);
        case 'currency':
            return formatCurrency(value, (options === null || options === void 0 ? void 0 : options.currencyDecimalPlaces) || 2);
        default:
            return value;
    }
};
/**
 * Check if a masked input needs validation
 * @param type The input mask type
 * @param value The current value
 * @returns Whether the value is valid or not
 */
const validateMaskedInput = (type, value) => {
    switch (type) {
        case 'expiryDate':
            // Only validate once we have at least 2 digits
            if (value.replace(/\D/g, '').length >= 2) {
                return isValidMonth(value);
            }
            return true;
        default:
            return true;
    }
};
/**
 * Format time input as HH:MM with real-time validation
 * Prevents invalid hour/minute values as user types
 * @param value The raw input value
 * @param format The time format ('12h' or '24h')
 * @returns The formatted time string (only valid digits are kept)
 */
const formatTimeInput = (value, format = '24h') => {
    const digitsOnly = value.replace(/\D/g, '');
    if (digitsOnly.length === 0)
        return '';
    const maxHourFirstDigit = format === '24h' ? 2 : 1;
    const maxHour = format === '24h' ? 23 : 12;
    const minHour = format === '12h' ? 1 : 0;
    // First digit of hour
    if (digitsOnly.length === 1) {
        const d = parseInt(digitsOnly[0], 10);
        if (d > maxHourFirstDigit)
            return ''; // reject
        return digitsOnly;
    }
    // Second digit of hour
    if (digitsOnly.length === 2) {
        const hour = parseInt(digitsOnly.slice(0, 2), 10);
        if (hour > maxHour || (format === '12h' && hour < minHour)) {
            return digitsOnly.slice(0, 1); // reject second digit
        }
        return `${digitsOnly}:`;
    }
    // First digit of minute
    if (digitsOnly.length === 3) {
        parseInt(digitsOnly.slice(0, 2), 10);
        const minTens = parseInt(digitsOnly[2], 10);
        if (minTens > 5)
            return `${digitsOnly.slice(0, 2)}:`; // reject — minute tens max is 5
        return `${digitsOnly.slice(0, 2)}:${digitsOnly.slice(2)}`;
    }
    // Second digit of minute (complete time)
    if (digitsOnly.length >= 4) {
        parseInt(digitsOnly.slice(0, 2), 10);
        const minute = parseInt(digitsOnly.slice(2, 4), 10);
        if (minute > 59) {
            return `${digitsOnly.slice(0, 2)}:${digitsOnly.slice(2, 3)}`; // reject fourth digit
        }
        return `${digitsOnly.slice(0, 2)}:${digitsOnly.slice(2, 4)}`;
    }
    return digitsOnly;
};
/**
 * Validate if a formatted time string is a complete, valid time
 * @param value The formatted time string (HH:MM)
 * @param format The time format ('12h' or '24h')
 * @returns Whether the time is valid and complete
 */
const isValidTimeInput = (value, format = '24h') => {
    if (value.length !== 5)
        return false;
    const match = value.match(/^(\d{2}):(\d{2})$/);
    if (!match)
        return false;
    const hour = parseInt(match[1], 10);
    const minute = parseInt(match[2], 10);
    if (minute < 0 || minute > 59)
        return false;
    if (format === '24h') {
        return hour >= 0 && hour <= 23;
    }
    else {
        return hour >= 1 && hour <= 12;
    }
};
/**
 * Get cursor position after applying a mask
 * This helps maintain the cursor position when formatting
 * @param previousValue Previous input value
 * @param currentValue Current formatted value
 * @param previousPosition Previous cursor position
 * @returns The new cursor position
 */
const getAdjustedCursorPosition = (previousValue, currentValue, previousPosition) => {
    // If values are the same, don't move cursor
    if (previousValue === currentValue) {
        return previousPosition;
    }
    // For currency formatting with commas
    // Count how many commas are before the cursor position in both values
    const prevCommasBefore = (previousValue.slice(0, previousPosition).match(/,/g) || []).length;
    const currCommasBefore = (currentValue.slice(0, previousPosition).match(/,/g) || []).length;
    // If commas were added or removed, adjust position
    if (prevCommasBefore !== currCommasBefore) {
        const commaDiff = currCommasBefore - prevCommasBefore;
        return previousPosition + commaDiff;
    }
    // For credit card formatting with hyphens
    if (previousValue.length < currentValue.length) {
        // Check if we're at a position where a separator was added
        if (currentValue.charAt(previousPosition) === '-') {
            // If we're at a separator, move cursor one position forward
            return previousPosition + 1;
        }
        // Handle case where we just entered the 4th, 8th, or 12th digit
        // and a separator was automatically added after it
        if (previousPosition === 4 || previousPosition === 9 || previousPosition === 14) {
            if (currentValue.charAt(previousPosition) === '-') {
                return previousPosition + 1;
            }
        }
    }
    // Check if digits were added at the end
    const prevDigits = previousValue.replace(/\D/g, '');
    const currDigits = currentValue.replace(/\D/g, '');
    if (currDigits.length > prevDigits.length) {
        // For credit card groups (after 4, 8, 12 digits)
        if (currDigits.length === 4 || currDigits.length === 8 || currDigits.length === 12) {
            // Find position after the hyphen that was just added
            const hyphenPos = currentValue.indexOf('-', previousPosition - 1);
            if (hyphenPos !== -1) {
                return hyphenPos + 1;
            }
        }
    }
    // Default cursor adjustment when something was added
    if (currentValue.length > previousValue.length) {
        const addedChars = currentValue.length - previousValue.length;
        return previousPosition + addedChars;
    }
    return previousPosition;
};

export { applyInputMask, formatCreditCard, formatCurrency, formatDateInput, formatExpiryDate, formatPhoneNumber, formatSSN, formatTimeInput, getAdjustedCursorPosition, isValidDateInput, isValidMonth, isValidTimeInput, validateMaskedInput };
