// @name        フォルダ横断 Grep
// @description 指定フォルダ内の複数ファイルをまとめて検索し、結果をレポートに出力します。
//              grep() API を使った複数ファイル対応の高度な検索スクリプトです。

run();

function run() {
    // ─── 検索対象フォルダの決定 ───────────────────────────────────
    var defaultFolder = "";
    if (phantis.isFileOpen()) {
        // 現在開いているファイルのフォルダをデフォルトにする
        var fp = phantis.getFilePath();
        defaultFolder = fp.replace(/[\\\/][^\\\/]+$/, "");
    }

    var folder = phantis.prompt(
        "検索対象フォルダのパスを入力してください:",
        defaultFolder
    );
    if (folder === null || folder.trim() === "") {
        phantis.setStatusMessage("キャンセルしました");
        return;
    }
    folder = folder.trim();

    // ─── ファイル一覧の確認 ───────────────────────────────────────
    var fileFilter = phantis.prompt(
        "ファイルフィルタを入力してください。\n" +
        "例: *.log, *.txt, *.log,*.txt （カンマ区切りで複数指定可）",
        "*.log,*.txt"
    );
    if (fileFilter === null) {
        phantis.setStatusMessage("キャンセルしました");
        return;
    }
    if (fileFilter.trim() === "") fileFilter = "*.*";

    var withSubdirs = phantis.confirm("サブフォルダも検索しますか？");

    // ファイル一覧を取得してプレビュー
    var files = phantis.listFiles(folder, fileFilter, withSubdirs);
    if (files.length === 0) {
        phantis.message(
            "フォルダ: " + folder + "\n\n" +
            "対象ファイルが見つかりませんでした。\n" +
            "フォルダパスとフィルタを確認してください。"
        );
        return;
    }

    var filePreview = "";
    var previewCount = Math.min(8, files.length);
    for (var i = 0; i < previewCount; i++) {
        filePreview += "  " + files[i].replace(/.*[\\\/]/, "") + "\n";
    }
    if (files.length > 8) filePreview += "  … 他 " + (files.length - 8) + " ファイル\n";

    if (!phantis.confirm(
        "対象ファイル: " + files.length + " 件\n\n" +
        filePreview + "\nこれらのファイルを検索しますか？"
    )) {
        phantis.setStatusMessage("キャンセルしました");
        return;
    }

    // ─── 検索パターンの入力 ───────────────────────────────────────
    var pattern = phantis.prompt(
        "検索するキーワードまたは正規表現を入力してください:",
        "ERROR"
    );
    if (pattern === null || pattern.trim() === "") {
        phantis.setStatusMessage("キャンセルしました");
        return;
    }
    pattern = pattern.trim();

    var useRegex = phantis.confirm("正規表現として扱いますか？");
    var caseSens = phantis.confirm("大文字/小文字を区別しますか？");

    // ─── 検索実行 ─────────────────────────────────────────────────
    phantis.setStatusMessage("検索中...");

    var hits = phantis.grep(folder, pattern, {
        regex:         useRegex,
        caseSensitive: caseSens,
        filter:        fileFilter,
        subdirs:       withSubdirs,
    });

    if (hits.length === 0) {
        phantis.message(
            "「" + pattern + "」はどのファイルにも見つかりませんでした。\n\n" +
            "フォルダ  : " + folder + "\n" +
            "フィルタ  : " + fileFilter + "\n" +
            "正規表現  : " + (useRegex ? "あり" : "なし")
        );
        phantis.setStatusMessage("0 件");
        return;
    }

    // ─── ヒットをファイル別に集計 ────────────────────────────────
    var byFile = {};
    var fileOrder = [];
    for (var i = 0; i < hits.length; i++) {
        var h = hits[i];
        var fname = h.file.replace(/.*[\\\/]/, "");
        if (!byFile[h.file]) {
            byFile[h.file] = [];
            fileOrder.push(h.file);
        }
        byFile[h.file].push(h);
    }

    var summary =
        "「" + pattern + "」の検索結果\n\n" +
        "フォルダ      : " + folder + "\n" +
        "フィルタ      : " + fileFilter + "\n" +
        "ヒット総数    : " + hits.length.toLocaleString() + " 件\n" +
        "ヒットファイル: " + fileOrder.length + " / " + files.length + " ファイル\n" +
        "──────────────────────────────────\n";

    var topFiles = fileOrder.slice(0, 10);
    for (var j = 0; j < topFiles.length; j++) {
        var fp2  = topFiles[j];
        var cnt  = byFile[fp2].length;
        var nm   = fp2.replace(/.*[\\\/]/, "");
        summary += "  " + nm + ": " + cnt + " 件\n";
    }
    if (fileOrder.length > 10) {
        summary += "  … 他 " + (fileOrder.length - 10) + " ファイル\n";
    }

    // ─── 結果の処理を選択 ─────────────────────────────────────────
    var action = phantis.selectItem(
        summary + "\n次のアクションを選択してください:",
        [
            "最初のヒットを開く",
            "TSV レポートをファイルに保存",
            "ヒット数トップファイルをリスト表示",
            "閉じる",
        ]
    );

    if (action === "最初のヒットを開く") {
        var first = hits[0];
        phantis.openFile(first.file);
        sleep(300);   // ファイルオープン完了を少し待つ
        phantis.scrollToOffset(first.offset);
        phantis.setStatusMessage(
            "「" + pattern + "」初ヒット: " + first.file.replace(/.*[\\\/]/, "") +
            " 行 " + first.line
        );

    } else if (action === "TSV レポートをファイルに保存") {
        var reportPath = saveReport(folder, pattern, hits);
        if (reportPath) {
            phantis.setStatusMessage("レポートを保存しました: " + reportPath);
            if (phantis.confirm("レポートを Phantis で開きますか？\n\n" + reportPath)) {
                phantis.openFile(reportPath);
            }
        }

    } else if (action === "ヒット数トップファイルをリスト表示") {
        var listMsg = "ヒット数トップ（全 " + fileOrder.length + " ファイル）:\n\n";
        // ヒット数降順にソート
        var sorted = fileOrder.slice().sort(function(a, b) {
            return byFile[b].length - byFile[a].length;
        });
        for (var k = 0; k < Math.min(15, sorted.length); k++) {
            var sp = sorted[k];
            listMsg += "  " + byFile[sp].length + " 件  " + sp.replace(/.*[\\\/]/, "") + "\n";
        }
        phantis.message(listMsg);
        phantis.setStatusMessage("Grep 完了: " + hits.length + " 件 / " + fileOrder.length + " ファイル");

    } else {
        phantis.setStatusMessage("Grep 完了: " + hits.length + " 件");
    }
}

function saveReport(folder, pattern, hits) {
    // 保存先: スクリプトと同じフォルダ、またはユーザー指定
    var scriptDir = phantis.getScriptDir();
    var defaultPath;
    if (scriptDir) {
        var safe = pattern.replace(/[\\\/:\*\?"<>\|]/g, "_").substring(0, 30);
        defaultPath = scriptDir.replace(/[\\\/]+$/, "") + "/" + safe + "_grep_report.tsv";
    } else {
        defaultPath = "grep_report.tsv";
    }

    var savePath = phantis.prompt("レポートの保存先パスを入力してください:", defaultPath);
    if (savePath === null || savePath.trim() === "") return null;
    savePath = savePath.trim();

    // TSV 形式で書き出し
    var lines = ["FilePath\tLineNumber\tOffset\tText"];
    for (var i = 0; i < hits.length; i++) {
        var h = hits[i];
        var text = h.text.replace(/\t/g, "  ");   // タブをスペースに置換
        lines.push(h.file + "\t" + h.line + "\t" + h.offset + "\t" + text);
    }

    phantis.writeFile(savePath, lines.join("\n"), "utf-8");
    return savePath;
}
