/**
 * Git Handler
 *
 * Handles Git operations for web clients.
 */
import { exec } from 'child_process';
import { promisify } from 'util';
import { dirname } from 'path';
const execAsync = promisify(exec);
// Git helper
async function execGit(cwd, args) {
    return execAsync(`git ${args}`, {
        cwd,
        encoding: 'utf-8',
        maxBuffer: 10 * 1024 * 1024,
    });
}
async function isGitRepo(cwd) {
    try {
        await execGit(cwd, 'rev-parse --git-dir');
        return true;
    }
    catch {
        return false;
    }
}
async function getRepoRoot(cwd) {
    try {
        const { stdout } = await execGit(cwd, 'rev-parse --show-toplevel');
        return stdout.trim();
    }
    catch {
        return null;
    }
}
function parseGitStatus(stdout) {
    const lines = stdout.trim().split('\n').filter(Boolean);
    const changes = [];
    for (const line of lines) {
        if (line.length < 4)
            continue;
        const x = line[0];
        const y = line[1];
        const filePath = line.slice(3);
        let status;
        let staged = false;
        if (x === 'A') {
            status = 'added';
            staged = true;
        }
        else if (x === 'M') {
            status = 'modified';
            staged = true;
        }
        else if (x === 'D') {
            status = 'deleted';
            staged = true;
        }
        else if (x === 'R') {
            status = 'renamed';
            staged = true;
        }
        else if (x === 'C') {
            status = 'copied';
            staged = true;
        }
        else if (y === 'A') {
            status = 'added';
        }
        else if (y === 'M') {
            status = 'modified';
        }
        else if (y === 'D') {
            status = 'deleted';
        }
        else if (y === '?') {
            status = 'untracked';
        }
        else
            continue;
        changes.push({ path: filePath, status, staged });
    }
    return changes;
}
// Git handler
export function setupGitHandler(ws, sessionId) {
    return (msg) => {
        const { type, id, method, args } = msg;
        switch (method) {
            case 'git:checkIgnore':
                handleCheckIgnore(ws, id, args);
                break;
            case 'git:checkIgnoreBatch':
                handleCheckIgnoreBatch(ws, id, args);
                break;
            case 'git:getRepoInfo':
                handleGetRepoInfo(ws, id, args);
                break;
            case 'git:getStatus':
                handleGetStatus(ws, id, args);
                break;
            case 'git:stage':
                handleStage(ws, id, args);
                break;
            case 'git:unstage':
                handleUnstage(ws, id, args);
                break;
            case 'git:discard':
                handleDiscard(ws, id, args);
                break;
            case 'git:commit':
                handleCommit(ws, id, args);
                break;
            case 'git:log':
                handleLog(ws, id, args);
                break;
            case 'git:branches':
                handleBranches(ws, id, args);
                break;
            case 'git:switchBranch':
                handleSwitchBranch(ws, id, args);
                break;
            case 'git:createBranch':
                handleCreateBranch(ws, id, args);
                break;
            case 'git:push':
                handlePush(ws, id, args);
                break;
            case 'git:pull':
                handlePull(ws, id, args);
                break;
            case 'git:fetch':
                handleFetch(ws, id, args);
                break;
            default:
                ws.send(JSON.stringify({ type: 'error', id, error: `Unknown git method: ${method}` }));
        }
    };
}
async function handleCheckIgnore(ws, id, args) {
    const filePath = args[0];
    const cwd = dirname(filePath);
    try {
        await execGit(cwd, `check-ignore "${filePath}"`);
        ws.send(JSON.stringify({ type: 'response', id, result: { isIgnored: true } }));
    }
    catch (error) {
        if (error.code === 1) {
            ws.send(JSON.stringify({ type: 'response', id, result: { isIgnored: false } }));
        }
        else {
            ws.send(JSON.stringify({ type: 'response', id, result: { isIgnored: false } }));
        }
    }
}
async function handleCheckIgnoreBatch(ws, id, args) {
    const filePaths = args[0] || [];
    if (filePaths.length === 0) {
        ws.send(JSON.stringify({ type: 'response', id, result: [] }));
        return;
    }
    const cwd = dirname(filePaths[0]);
    try {
        const pathsArg = filePaths.map(p => `"${p}"`).join(' ');
        const { stdout } = await execGit(cwd, `check-ignore ${pathsArg}`);
        const ignoredPaths = new Set(stdout.trim().split('\n').filter(Boolean));
        const result = filePaths.map(path => ({ path, isIgnored: ignoredPaths.has(path) }));
        ws.send(JSON.stringify({ type: 'response', id, result }));
    }
    catch {
        const result = filePaths.map(path => ({ path, isIgnored: false }));
        ws.send(JSON.stringify({ type: 'response', id, result }));
    }
}
async function handleGetRepoInfo(ws, id, args) {
    const cwd = args[0];
    try {
        const isRepo = await isGitRepo(cwd);
        if (!isRepo) {
            ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false } }));
            return;
        }
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false } }));
            return;
        }
        let branch = 'unknown';
        try {
            const { stdout } = await execGit(root, 'rev-parse --abbrev-ref HEAD');
            branch = stdout.trim();
        }
        catch { }
        let remoteUrl = '';
        try {
            const { stdout } = await execGit(root, 'remote get-url origin');
            remoteUrl = stdout.trim();
        }
        catch { }
        ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: true, root, branch, remoteUrl } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false, error: error.message } }));
    }
}
async function handleGetStatus(ws, id, args) {
    const cwd = args[0];
    try {
        const isRepo = await isGitRepo(cwd);
        if (!isRepo) {
            ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false, changes: [] } }));
            return;
        }
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false, changes: [] } }));
            return;
        }
        const { stdout } = await execGit(root, 'status --porcelain');
        const changes = parseGitStatus(stdout);
        ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: true, root, changes } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { isRepo: false, changes: [], error: error.message } }));
    }
}
async function handleStage(ws, id, args) {
    const cwd = args[0];
    const filePaths = args[1] || [];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        const pathsArg = filePaths.map(p => `"${p}"`).join(' ');
        await execGit(root, `add ${pathsArg}`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleUnstage(ws, id, args) {
    const cwd = args[0];
    const filePaths = args[1] || [];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        const pathsArg = filePaths.map(p => `"${p}"`).join(' ');
        await execGit(root, `reset HEAD ${pathsArg}`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleDiscard(ws, id, args) {
    const cwd = args[0];
    const filePath = args[1];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `checkout -- "${filePath}"`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleCommit(ws, id, args) {
    const cwd = args[0];
    const message = args[1];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        const escapedMessage = message.replace(/"/g, '\\"');
        await execGit(root, `commit -m "${escapedMessage}"`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleLog(ws, id, args) {
    const cwd = args[0];
    const limit = args[1] || 50;
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        const format = '%H|%an|%ae|%ad|%s';
        const { stdout } = await execGit(root, `log --pretty=format:"${format}" --date=short -n ${limit}`);
        const commits = stdout.trim().split('\n').filter(Boolean).map(line => {
            const [hash, author, email, date, ...messageParts] = line.split('|');
            return { hash, author, email, date, message: messageParts.join('|') };
        });
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true, commits } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleBranches(ws, id, args) {
    const cwd = args[0];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        const { stdout } = await execGit(root, 'branch -a --format="%(refname:short)|%(HEAD)"');
        const branches = stdout.trim().split('\n').filter(Boolean).map(line => {
            const [name, isCurrent] = line.split('|');
            return { name, current: isCurrent === '*' };
        });
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true, branches } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleSwitchBranch(ws, id, args) {
    const cwd = args[0];
    const branchName = args[1];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `checkout "${branchName}"`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleCreateBranch(ws, id, args) {
    const cwd = args[0];
    const branchName = args[1];
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `checkout -b "${branchName}"`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handlePush(ws, id, args) {
    const cwd = args[0];
    const remote = args[1] || 'origin';
    const branch = args[2] || '';
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `push ${remote} ${branch}`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handlePull(ws, id, args) {
    const cwd = args[0];
    const remote = args[1] || 'origin';
    const branch = args[2] || '';
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `pull ${remote} ${branch}`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
async function handleFetch(ws, id, args) {
    const cwd = args[0];
    const remote = args[1] || 'origin';
    try {
        const root = await getRepoRoot(cwd);
        if (!root) {
            ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: 'Not a git repository' } }));
            return;
        }
        await execGit(root, `fetch ${remote}`);
        ws.send(JSON.stringify({ type: 'response', id, result: { success: true } }));
    }
    catch (error) {
        ws.send(JSON.stringify({ type: 'response', id, result: { success: false, error: error.message } }));
    }
}
//# sourceMappingURL=git.js.map