import { OutputChannel } from "vscode";
import { execSync } from "child_process";

// Types and Interfaces
export interface ErrorContext {
    imageTag?: string;
    containerImageName?: string;
    toolVersion?: string;
}

type ErrorHandler = string | ((context: ErrorContext, outputChannel: OutputChannel) => void);

const DOCKER_ERROR_MESSAGES: Record<string, ErrorHandler> = {
    "Cannot connect to the Docker daemon": " 🐋 Docker is not running or not accessible. Please start Docker and try again.",
    "Docker is not running": " 🐋 Docker is not running or not accessible. Please start Docker and try again.",
    "No such image": (context, outputChannel) => {
        if (context.imageTag) {
            outputChannel.appendLine(`Scanner image ${context.imageTag} not found locally. Attempting to download...`);
            outputChannel.appendLine('');
        }
    },
    "Unable to find image": "📦 Container image not found. The image will be downloaded automatically.",
    "manifest unknown": (context, outputChannel) => {
        if (context.containerImageName && context.toolVersion) {
            outputChannel.appendLine(`⚠️ Please verify that version ${context.toolVersion} exists for image ${context.containerImageName}. You may need to check available versions or update your configuration.`);
            outputChannel.appendLine('');
        }
    },
    "manifest is not known to the registry": (context, outputChannel) => {
        if (context.containerImageName && context.toolVersion) {
            outputChannel.appendLine(`⚠️ Please verify that version ${context.toolVersion} exists for image ${context.containerImageName}. You may need to check available versions or update your configuration.`);
            outputChannel.appendLine('');
        }
    },
    "unknown flag": "⚠️ Invalid Docker command: Unknown flag or option. Please check the Docker command syntax.",
    "unknown shorthand flag": "⚠️ Invalid Docker command: Unknown shorthand flag. Please verify the command flags.",
    "docker: command not found": "❌ Docker command not found. Please ensure Docker is installed and in your PATH.",
    "permission denied": "🔒 Permission denied while accessing Docker. Please check your Docker permissions or run with appropriate privileges.",
    "error during connect": "🔌 Error connecting to Docker. Please verify Docker is running and accessible.",
    "request cancelled": () => { throw new Error("Scan operation cancelled."); }
};

/**
 * DockerService - Consolidated service for Docker operations and error handling
 * Combines functionality from DockerErrorHandler and DockerValidator
 */
export class DockerService {
    private lastErrorKey: string | null = null;
    private lastErrorCategory: 'critical-docker' | 'docker' | null = null;

    // ===== Docker Validation Methods =====

    /**
     * Checks if Docker is installed and accessible
     */
    static isDockerInstalled(containerEnginePath: string, outputChannel: OutputChannel): boolean {
        try {
            execSync(`${containerEnginePath} --version`, { stdio: 'ignore' });
            return true;
        } catch (err) {
            outputChannel.appendLine('❌ Docker is not installed or not found in the PATH. Please install Docker to continue.');
            return false;
        }
    }

    // ===== Error Handling Methods =====

    public static getErrorPatterns(): string[] {
        return Object.keys(DOCKER_ERROR_MESSAGES);
    }

    public getLastErrorCategory(): 'critical-docker' | 'docker' | null {
        return this.lastErrorCategory;
    }

    handle(errorMessage: string, outputChannel: OutputChannel, context: ErrorContext = {}, logCapture?: (message: string) => void): void {
        const errorKey = this.findMatchingErrorKey(errorMessage);

        if (errorKey) {
            if (this.isDuplicateError(errorKey)) {
                return;
            }
            this.lastErrorKey = errorKey;

            const criticalPatterns = [
                'Cannot connect to the Docker daemon',
                'Docker is not running',
                'docker: command not found',
                'error during connect'
            ];
            this.lastErrorCategory = criticalPatterns.includes(errorKey) ? 'critical-docker' : 'docker';

            this.executeErrorHandler(errorKey, context, outputChannel, logCapture);
            return;
        }

        this.handleGenericError(errorMessage, context, outputChannel);
        this.lastErrorCategory = 'docker';
    }

    reset(): void {
        this.lastErrorKey = null;
        this.lastErrorCategory = null;
    }

    private findMatchingErrorKey(errorMessage: string): string | null {
        for (const key in DOCKER_ERROR_MESSAGES) {
            if (errorMessage.includes(key)) {
                return key;
            }
        }
        return null;
    }

    private isDuplicateError(errorKey: string): boolean {
        return this.lastErrorKey === errorKey;
    }

    private executeErrorHandler(errorKey: string, context: ErrorContext, outputChannel: OutputChannel, logCapture?: (message: string) => void): void {
        const handler = DOCKER_ERROR_MESSAGES[errorKey];
        if (typeof handler === "string") {
            outputChannel.appendLine(handler);
            if (logCapture) {
                logCapture(handler);
            }
        } else {
            handler(context, outputChannel);
        }
    }

    private handleGenericError(errorMessage: string, context: ErrorContext, outputChannel: OutputChannel): void {
        this.lastErrorKey = null;
        if (context.imageTag) {
            outputChannel.appendLine(`Error checking for scanner image ${context.imageTag}: ${errorMessage}`);
        } else {
            outputChannel.appendLine(`❌ Failed to ensure scanner image is available. Please verify that the specified image version exists.`);
        }
    }
}
