"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFlaskVersionBucket = exports.IGNORE_PATTERNS = exports.FlaskProjectType = void 0;
exports.getFlaskVersion = getFlaskVersion;
exports.getFlaskProjectType = getFlaskProjectType;
exports.getFlaskProjectTypeName = getFlaskProjectTypeName;
exports.findFlaskAppFile = findFlaskAppFile;
const fast_glob_1 = __importDefault(require("fast-glob"));
const ui_1 = require("../../ui");
const semver_1 = require("../../utils/semver");
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
var FlaskProjectType;
(function (FlaskProjectType) {
    FlaskProjectType["STANDARD"] = "standard";
    FlaskProjectType["RESTFUL"] = "restful";
    FlaskProjectType["RESTX"] = "restx";
    FlaskProjectType["SMOREST"] = "smorest";
    FlaskProjectType["BLUEPRINT"] = "blueprint";
})(FlaskProjectType || (exports.FlaskProjectType = FlaskProjectType = {}));
exports.IGNORE_PATTERNS = [
    '**/node_modules/**',
    '**/dist/**',
    '**/build/**',
    '**/venv/**',
    '**/.venv/**',
    '**/env/**',
    '**/.env/**',
    '**/__pycache__/**',
    '**/migrations/**',
    '**/instance/**',
];
/**
 * Get Flask version bucket for analytics
 */
exports.getFlaskVersionBucket = (0, semver_1.createVersionBucket)();
/**
 * Extract Flask version from requirements files or pyproject.toml
 */
async function getFlaskVersion(options) {
    const { installDir } = options;
    // Check requirements files
    const requirementsFiles = await (0, fast_glob_1.default)(['**/requirements*.txt', '**/pyproject.toml', '**/setup.py', '**/Pipfile'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const reqFile of requirementsFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, reqFile), 'utf-8');
            // Try to extract version from requirements.txt format (Flask==3.0.0 or flask>=2.0)
            const requirementsMatch = content.match(/[Ff]lask[=<>~!]+([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
            if (requirementsMatch) {
                return requirementsMatch[1];
            }
            // Try to extract from pyproject.toml format
            const pyprojectMatch = content.match(/[Ff]lask["\s]*[=<>~!]+\s*["']?([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
            if (pyprojectMatch) {
                return pyprojectMatch[1];
            }
        }
        catch {
            // Skip files that can't be read
            continue;
        }
    }
    return undefined;
}
/**
 * Check if Flask-RESTful is installed
 */
async function hasFlaskRESTful({ installDir, }) {
    const requirementsFiles = await (0, fast_glob_1.default)(['**/requirements*.txt', '**/pyproject.toml', '**/Pipfile'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const reqFile of requirementsFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, reqFile), 'utf-8');
            if (content.includes('flask-restful') ||
                content.includes('Flask-RESTful')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    // Also check imports in Python files
    const pyFiles = await (0, fast_glob_1.default)(['**/*.py'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const pyFile of pyFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, pyFile), 'utf-8');
            if (content.includes('from flask_restful import') ||
                content.includes('import flask_restful')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    return false;
}
/**
 * Check if Flask-RESTX is installed
 */
async function hasFlaskRESTX({ installDir, }) {
    const requirementsFiles = await (0, fast_glob_1.default)(['**/requirements*.txt', '**/pyproject.toml', '**/Pipfile'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const reqFile of requirementsFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, reqFile), 'utf-8');
            if (content.includes('flask-restx') || content.includes('Flask-RESTX')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    // Also check imports in Python files
    const pyFiles = await (0, fast_glob_1.default)(['**/*.py'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const pyFile of pyFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, pyFile), 'utf-8');
            if (content.includes('from flask_restx import') ||
                content.includes('import flask_restx')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    return false;
}
/**
 * Check if flask-smorest is installed
 */
async function hasFlaskSmorest({ installDir, }) {
    const requirementsFiles = await (0, fast_glob_1.default)(['**/requirements*.txt', '**/pyproject.toml', '**/Pipfile'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const reqFile of requirementsFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, reqFile), 'utf-8');
            if (content.includes('flask-smorest')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    // Also check imports in Python files
    const pyFiles = await (0, fast_glob_1.default)(['**/*.py'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const pyFile of pyFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, pyFile), 'utf-8');
            if (content.includes('from flask_smorest import') ||
                content.includes('import flask_smorest')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    return false;
}
/**
 * Check if app uses Flask Blueprints
 */
async function hasBlueprints({ installDir, }) {
    const pyFiles = await (0, fast_glob_1.default)(['**/*.py'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const pyFile of pyFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, pyFile), 'utf-8');
            if (content.includes('Blueprint(') ||
                content.includes('register_blueprint(') ||
                content.includes('from flask import Blueprint')) {
                return true;
            }
        }
        catch {
            continue;
        }
    }
    return false;
}
/**
 * Detect Flask project type
 */
async function getFlaskProjectType(options) {
    const { installDir } = options;
    // Check for Flask-RESTX first (most specific - includes Swagger)
    if (await hasFlaskRESTX({ installDir })) {
        (0, ui_1.getUI)().setDetectedFramework('Flask-RESTX');
        return FlaskProjectType.RESTX;
    }
    // Check for flask-smorest (OpenAPI-first)
    if (await hasFlaskSmorest({ installDir })) {
        (0, ui_1.getUI)().setDetectedFramework('flask-smorest');
        return FlaskProjectType.SMOREST;
    }
    // Check for Flask-RESTful
    if (await hasFlaskRESTful({ installDir })) {
        (0, ui_1.getUI)().setDetectedFramework('Flask-RESTful');
        return FlaskProjectType.RESTFUL;
    }
    // Check for Blueprints (large app structure)
    if (await hasBlueprints({ installDir })) {
        (0, ui_1.getUI)().setDetectedFramework('Flask with Blueprints');
        return FlaskProjectType.BLUEPRINT;
    }
    // Default to standard Flask
    (0, ui_1.getUI)().setDetectedFramework('Flask');
    return FlaskProjectType.STANDARD;
}
/**
 * Get human-readable name for Flask project type
 */
function getFlaskProjectTypeName(projectType) {
    switch (projectType) {
        case FlaskProjectType.STANDARD:
            return 'Standard Flask';
        case FlaskProjectType.RESTFUL:
            return 'Flask-RESTful';
        case FlaskProjectType.RESTX:
            return 'Flask-RESTX';
        case FlaskProjectType.SMOREST:
            return 'flask-smorest';
        case FlaskProjectType.BLUEPRINT:
            return 'Flask with Blueprints';
    }
}
/**
 * Find the main Flask app file
 */
async function findFlaskAppFile(options) {
    const { installDir } = options;
    // Common Flask app file patterns
    const commonPatterns = [
        '**/app.py',
        '**/wsgi.py',
        '**/application.py',
        '**/run.py',
        '**/main.py',
        '**/__init__.py',
    ];
    const appFiles = await (0, fast_glob_1.default)(commonPatterns, {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    // Look for files with Flask() instantiation or create_app() factory
    for (const appFile of appFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, appFile), 'utf-8');
            // Check for Flask app instantiation or application factory
            if (content.includes('Flask(__name__)') ||
                content.includes('Flask(') ||
                content.includes('def create_app(')) {
                return appFile;
            }
        }
        catch {
            continue;
        }
    }
    // If no file with Flask() found, check all Python files
    const allPyFiles = await (0, fast_glob_1.default)(['**/*.py'], {
        cwd: installDir,
        ignore: exports.IGNORE_PATTERNS,
    });
    for (const pyFile of allPyFiles) {
        try {
            const content = fs.readFileSync(path.join(installDir, pyFile), 'utf-8');
            if (content.includes('Flask(__name__)') ||
                content.includes('def create_app(')) {
                return pyFile;
            }
        }
        catch {
            continue;
        }
    }
    // Return first common pattern file if exists
    if (appFiles.length > 0) {
        return appFiles[0];
    }
    return undefined;
}
