import { minimatch } from "../../deps.js";
import { getCurrentGitBranch, isGitRepository } from "../utils/git.js";
import { isFileResource } from "../utils/utils.js";
import { TRIGGER_TYPES } from "../types.js";
// Define all branch-specific file types (computed lazily)
function getBranchSpecificTypes() {
    return {
        variable: '.variable.yaml',
        resource: '.resource.yaml',
        // Generate trigger patterns from the list
        ...Object.fromEntries(TRIGGER_TYPES.map(t => [`${t}_trigger`, `.${t}_trigger.yaml`]))
    };
}
/**
 * Check if a path ends with any trigger type
 */
function isTriggerFile(path) {
    return TRIGGER_TYPES.some(type => path.endsWith(`.${type}_trigger.yaml`));
}
/**
 * Extract the file type suffix from a path
 */
function getFileTypeSuffix(path) {
    for (const [_, suffix] of Object.entries(getBranchSpecificTypes())) {
        if (path.endsWith(suffix)) {
            return suffix;
        }
    }
    const resourceFileMatch = path.match(/(\\.resource\\.file\\..+)$/);
    if (resourceFileMatch) {
        return resourceFileMatch[1];
    }
    return null;
}
/**
 * Build regex pattern for all supported yaml file types
 */
function buildYamlTypePattern() {
    const basicTypes = ['variable', 'resource'];
    const triggerTypes = TRIGGER_TYPES.map(t => `${t}_trigger`);
    return `((${basicTypes.join('|')})|(${triggerTypes.join('|')}))`;
}
/**
 * Get the specific items configuration for the current git branch
 * Merges commonSpecificItems with branch-specific specificItems
 */
export function getSpecificItemsForCurrentBranch(config, branchOverride) {
    if (!config.gitBranches) {
        return undefined;
    }
    // Use branch override if provided, otherwise detect from git
    let currentBranch = null;
    if (branchOverride) {
        currentBranch = branchOverride;
    }
    else if (isGitRepository()) {
        currentBranch = getCurrentGitBranch();
    }
    if (!currentBranch) {
        return undefined;
    }
    const commonItems = config.gitBranches.commonSpecificItems;
    const branchItems = config.gitBranches[currentBranch]?.specificItems;
    // If neither common nor branch-specific items exist, return undefined
    if (!commonItems && !branchItems) {
        return undefined;
    }
    // Merge common and branch-specific items
    const merged = {};
    // Add common items
    if (commonItems?.variables) {
        merged.variables = [...commonItems.variables];
    }
    if (commonItems?.resources) {
        merged.resources = [...commonItems.resources];
    }
    if (commonItems?.triggers) {
        merged.triggers = [...commonItems.triggers];
    }
    if (commonItems?.folders) {
        merged.folders = [...commonItems.folders];
    }
    if (commonItems?.settings !== undefined) {
        merged.settings = commonItems.settings;
    }
    // Add branch-specific items (extending common items)
    if (branchItems?.variables) {
        merged.variables = [...(merged.variables || []), ...branchItems.variables];
    }
    if (branchItems?.resources) {
        merged.resources = [...(merged.resources || []), ...branchItems.resources];
    }
    if (branchItems?.triggers) {
        merged.triggers = [...(merged.triggers || []), ...branchItems.triggers];
    }
    if (branchItems?.folders) {
        merged.folders = [...(merged.folders || []), ...branchItems.folders];
    }
    // For settings (boolean), branch-specific overrides common
    if (branchItems?.settings !== undefined) {
        merged.settings = branchItems.settings;
    }
    return merged;
}
/**
 * Check if a path matches any of the patterns in the given list
 */
function matchesPatterns(path, patterns) {
    return patterns.some(pattern => minimatch(path, pattern));
}
/**
 * Check if a file path should be treated as branch-specific
 */
export function isSpecificItem(path, specificItems) {
    if (!specificItems) {
        return false;
    }
    // Determine the item type from the file path
    if (path.endsWith('.variable.yaml')) {
        return specificItems.variables ? matchesPatterns(path, specificItems.variables) : false;
    }
    if (path.endsWith('.resource.yaml')) {
        return specificItems.resources ? matchesPatterns(path, specificItems.resources) : false;
    }
    // Check for any trigger type
    if (isTriggerFile(path)) {
        return specificItems.triggers ? matchesPatterns(path, specificItems.triggers) : false;
    }
    // Check for folder meta files
    if (path.endsWith('/folder.meta.yaml')) {
        if (specificItems.folders) {
            // Match against the folder path (without /folder.meta.yaml)
            const folderPath = path.slice(0, -'/folder.meta.yaml'.length);
            return matchesPatterns(folderPath, specificItems.folders);
        }
        return false;
    }
    // Check for settings.yaml (root-level file)
    if (path === 'settings.yaml') {
        return specificItems.settings === true;
    }
    // Check for resource files using the standard detection function
    if (isFileResource(path)) {
        // Extract the base path without the file extension to match against patterns
        const basePathMatch = path.match(/^(.+?)\.resource\.file\./);
        if (basePathMatch && specificItems.resources) {
            const basePath = basePathMatch[1] + '.resource.yaml';
            return matchesPatterns(basePath, specificItems.resources);
        }
    }
    return false;
}
/**
 * Convert a base path to a branch-specific path
 */
export function toBranchSpecificPath(basePath, branchName) {
    // Sanitize branch name to be filesystem-safe
    const sanitizedBranchName = branchName.replace(/[\/\\:*?"<>|.]/g, '_');
    // Warn about potential collisions if sanitization occurred
    if (sanitizedBranchName !== branchName) {
        console.warn(`Warning: Branch name "${branchName}" contains filesystem-unsafe characters (/ \\ : * ? " < > | .) and was sanitized to "${sanitizedBranchName}". This may cause collisions with other similarly named branches.`);
    }
    // Check for folder meta file pattern: folder.meta.yaml -> folder.branchName.meta.yaml
    if (basePath.endsWith('/folder.meta.yaml')) {
        const pathWithoutMeta = basePath.substring(0, basePath.length - '/folder.meta.yaml'.length);
        return `${pathWithoutMeta}/folder.${sanitizedBranchName}.meta.yaml`;
    }
    // Check for settings.yaml: settings.yaml -> settings.branchName.yaml
    if (basePath === 'settings.yaml') {
        return `settings.${sanitizedBranchName}.yaml`;
    }
    // Check for resource file pattern (e.g., .resource.file.ini)
    const resourceFileMatch = basePath.match(/^(.+?)(\.resource\.file\..+)$/);
    let extension;
    let pathWithoutExtension;
    if (resourceFileMatch) {
        // Handle resource files
        extension = resourceFileMatch[2];
        pathWithoutExtension = resourceFileMatch[1];
    }
    else {
        const suffix = getFileTypeSuffix(basePath);
        if (!suffix) {
            return basePath;
        }
        extension = suffix;
        pathWithoutExtension = basePath.substring(0, basePath.length - extension.length);
    }
    return `${pathWithoutExtension}.${sanitizedBranchName}${extension}`;
}
/**
 * Convert a branch-specific path back to a base path
 */
export function fromBranchSpecificPath(branchSpecificPath, branchName) {
    // Sanitize branch name the same way as in toBranchSpecificPath
    const sanitizedBranchName = branchName.replace(/[\/\\:*?"<>|.]/g, '_');
    const escapedBranchName = sanitizedBranchName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    // Check for folder meta file pattern: /folder.branchName.meta.yaml -> /folder.meta.yaml
    const folderPattern = new RegExp(`/folder\\.${escapedBranchName}\\.meta\\.yaml$`);
    if (folderPattern.test(branchSpecificPath)) {
        return branchSpecificPath.replace(folderPattern, '/folder.meta.yaml');
    }
    // Check for settings file pattern: settings.branchName.yaml -> settings.yaml
    const settingsPattern = new RegExp(`^settings\\.${escapedBranchName}\\.yaml$`);
    if (settingsPattern.test(branchSpecificPath)) {
        return 'settings.yaml';
    }
    // Check for resource file pattern
    const resourceFilePattern = new RegExp(`\\.${escapedBranchName}(\\.resource\\.file\\..+)$`);
    const resourceFileMatch = branchSpecificPath.match(resourceFilePattern);
    if (resourceFileMatch) {
        const extension = resourceFileMatch[1];
        const pathWithoutBranchAndExtension = branchSpecificPath.substring(0, branchSpecificPath.length - `.${sanitizedBranchName}${extension}`.length);
        return `${pathWithoutBranchAndExtension}${extension}`;
    }
    const yamlPattern = new RegExp(`\\.${escapedBranchName}(\\.${buildYamlTypePattern()}\\.yaml)$`);
    const yamlMatch = branchSpecificPath.match(yamlPattern);
    if (!yamlMatch) {
        return branchSpecificPath; // Return unchanged if not a branch-specific path
    }
    const extension = yamlMatch[1];
    const pathWithoutBranchAndExtension = branchSpecificPath.substring(0, branchSpecificPath.length - `.${sanitizedBranchName}${extension}`.length);
    return `${pathWithoutBranchAndExtension}${extension}`;
}
/**
 * Get the branch-specific path for the current branch if the item should be branch-specific
 */
export function getBranchSpecificPath(basePath, specificItems, branchOverride) {
    if (!specificItems) {
        return undefined;
    }
    // Use branch override if provided, otherwise detect from git
    let currentBranch = null;
    if (branchOverride) {
        currentBranch = branchOverride;
    }
    else if (isGitRepository()) {
        currentBranch = getCurrentGitBranch();
    }
    if (!currentBranch) {
        return undefined;
    }
    if (isSpecificItem(basePath, specificItems)) {
        return toBranchSpecificPath(basePath, currentBranch);
    }
    return undefined;
}
// Cache for compiled regex patterns to avoid recompilation
const branchPatternCache = new Map();
/**
 * Check if a path is a branch-specific file for the current branch
 */
export function isCurrentBranchFile(path, branchOverride) {
    // Use branch override if provided, otherwise detect from git
    let currentBranch = null;
    if (branchOverride) {
        currentBranch = branchOverride;
    }
    else if (isGitRepository()) {
        currentBranch = getCurrentGitBranch();
    }
    if (!currentBranch) {
        return false;
    }
    // Sanitize branch name to match what would be used in file naming
    const sanitizedBranchName = currentBranch.replace(/[\/\\:*?"<>|.]/g, '_');
    const escapedBranchName = sanitizedBranchName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    // Use cached pattern or create and cache new one
    let pattern = branchPatternCache.get(currentBranch);
    if (!pattern) {
        pattern = new RegExp(`\\.${escapedBranchName}\\.${buildYamlTypePattern()}\\.yaml$|` +
            `\\.${escapedBranchName}\\.resource\\.file\\..+$|` +
            `/folder\\.${escapedBranchName}\\.meta\\.yaml$|` +
            `^settings\\.${escapedBranchName}\\.yaml$`);
        branchPatternCache.set(currentBranch, pattern);
    }
    return pattern.test(path);
}
/**
 * Check if a path is a branch-specific file for ANY branch (not necessarily current)
 * Used to identify and skip files from other branches during sync operations
 */
export function isBranchSpecificFile(path) {
    const yamlTypePattern = buildYamlTypePattern();
    return new RegExp(`\\.[^.]+\\.${yamlTypePattern}\\.yaml$|` +
        `\\.[^.]+\\.resource\\.file\\..+$|` +
        `/folder\\.[^.]+\\.meta\\.yaml$|` +
        `^settings\\.[^.]+\\.yaml$`).test(path);
}
