/**
 * @file Helpers.js
 * @description Utility helper functions
 * @author Implementation Team
 */

import { BOARD_SIZE, FILES, RANKS, COLORS } from './Constants.js';

/**
 * Check if a position is within board boundaries
 *
 * @param {number} row - Row coordinate (0-7)
 * @param {number} col - Column coordinate (0-7)
 * @returns {boolean} True if position is valid
 */
export function isValidPosition(row, col) {
    return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
}

/**
 * Convert position to algebraic notation
 *
 * @param {number} row - Row coordinate (0-7)
 * @param {number} col - Column coordinate (0-7)
 * @returns {string} Algebraic notation (e.g., "e4")
 *
 * @example
 * positionToAlgebraic(7, 4); // "e1"
 * positionToAlgebraic(0, 0); // "a8"
 */
export function positionToAlgebraic(row, col) {
    return FILES[col] + RANKS[row];
}

/**
 * Convert algebraic notation to position
 *
 * @param {string} notation - Algebraic notation (e.g., "e4")
 * @returns {{row: number, col: number}} Position object
 *
 * @example
 * algebraicToPosition("e4"); // {row: 4, col: 4}
 */
export function algebraicToPosition(notation) {
    const file = notation[0];
    const rank = notation[1];

    return {
        row: RANKS.indexOf(rank),
        col: FILES.indexOf(file)
    };
}

/**
 * Get opposite color
 *
 * @param {string} color - 'white' or 'black'
 * @returns {string} Opposite color
 */
export function getOppositeColor(color) {
    return color === COLORS.WHITE ? COLORS.BLACK : COLORS.WHITE;
}

/**
 * Deep clone a 2D array
 *
 * @param {Array<Array>} arr - 2D array to clone
 * @returns {Array<Array>} Cloned array
 */
export function deepClone2DArray(arr) {
    return arr.map(row => row.map(cell => {
        if (cell && typeof cell === 'object' && cell.clone) {
            return cell.clone();
        }
        return cell;
    }));
}

/**
 * Check if two positions are equal
 *
 * @param {{row: number, col: number}} pos1 - First position
 * @param {{row: number, col: number}} pos2 - Second position
 * @returns {boolean} True if positions are equal
 */
export function positionsEqual(pos1, pos2) {
    return pos1.row === pos2.row && pos1.col === pos2.col;
}

/**
 * Calculate distance between two positions
 *
 * @param {{row: number, col: number}} pos1 - First position
 * @param {{row: number, col: number}} pos2 - Second position
 * @returns {number} Distance (Chebyshev distance)
 */
export function getDistance(pos1, pos2) {
    return Math.max(
        Math.abs(pos1.row - pos2.row),
        Math.abs(pos1.col - pos2.col)
    );
}

/**
 * Check if two positions are on the same diagonal
 *
 * @param {{row: number, col: number}} pos1 - First position
 * @param {{row: number, col: number}} pos2 - Second position
 * @returns {boolean} True if on same diagonal
 */
export function onSameDiagonal(pos1, pos2) {
    return Math.abs(pos1.row - pos2.row) === Math.abs(pos1.col - pos2.col);
}

/**
 * Check if two positions are on the same row or column
 *
 * @param {{row: number, col: number}} pos1 - First position
 * @param {{row: number, col: number}} pos2 - Second position
 * @returns {boolean} True if on same row or column
 */
export function onSameRowOrColumn(pos1, pos2) {
    return pos1.row === pos2.row || pos1.col === pos2.col;
}

/**
 * Get direction between two positions
 *
 * @param {{row: number, col: number}} from - Starting position
 * @param {{row: number, col: number}} to - Ending position
 * @returns {{row: number, col: number}|null} Direction vector or null
 */
export function getDirection(from, to) {
    const rowDiff = to.row - from.row;
    const colDiff = to.col - from.col;

    if (rowDiff === 0 && colDiff === 0) {
        return null;
    }

    return {
        row: rowDiff === 0 ? 0 : rowDiff / Math.abs(rowDiff),
        col: colDiff === 0 ? 0 : colDiff / Math.abs(colDiff)
    };
}

/**
 * Debounce function to limit execution rate
 *
 * @param {Function} func - Function to debounce
 * @param {number} wait - Wait time in milliseconds
 * @returns {Function} Debounced function
 */
export function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

/**
 * Throttle function to limit execution frequency
 *
 * @param {Function} func - Function to throttle
 * @param {number} limit - Time limit in milliseconds
 * @returns {Function} Throttled function
 */
export function throttle(func, limit) {
    let inThrottle;
    return function executedFunction(...args) {
        if (!inThrottle) {
            func(...args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

/**
 * Generate unique ID
 *
 * @returns {string} Unique identifier
 */
export function generateId() {
    return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}

export default {
    isValidPosition,
    positionToAlgebraic,
    algebraicToPosition,
    getOppositeColor,
    deepClone2DArray,
    positionsEqual,
    getDistance,
    onSameDiagonal,
    onSameRowOrColumn,
    getDirection,
    debounce,
    throttle,
    generateId
};
