# app.py

import streamlit as st
import tempfile
import shutil
from pathlib import Path
import git  # GitPython
from core.file_scanner import FileScanner, FileInfo

# =====================================
# セッション状態の初期化
# =====================================
if 'scanned_files' not in st.session_state:
    st.session_state.scanned_files = []  # スキャンしたFileInfoリスト
if 'selected_files' not in st.session_state:
    st.session_state.selected_files = set()  # ユーザーが選択中のファイルパス (相対パス)
if 'cloned_repo_dir' not in st.session_state:
    st.session_state.cloned_repo_dir = None  # クローン先ディレクトリの絶対パス文字列

# =====================================
# タイトル等
# =====================================
st.title("Gitリポジトリ スキャナー")
st.markdown("**ディレクトリ構造をツリー表示し、ファイルを選んでMarkdownダウンロードできます**\n(**ワイドモード推奨**)")

# =====================================
# ツリー構造を生成する関数
# =====================================
def build_tree(paths):
    """
    相対パス(Pathオブジェクト)のリストからツリー状のネスト構造を構築する。
    戻り値は {要素名 -> 子要素のdict or None} という入れ子の辞書。
    """
    tree = {}
    for p in paths:
        parts = p.parts
        current = tree
        for i, part in enumerate(parts):
            if i == len(parts) - 1:
                # ファイルやフォルダの末端
                current[part] = None
            else:
                if part not in current:
                    current[part] = {}
                if isinstance(current[part], dict):
                    current = current[part]
                else:
                    # もしNoneだった場合(同名のファイル/フォルダがあるなど) → 無理やりdictに
                    current[part] = {}
                    current = current[part]
    return tree

def format_tree(tree_dict, prefix=""):
    """
    build_tree()で作ったネスト構造をASCIIアートのツリー文字列にする。
    """
    lines = []
    entries = sorted(tree_dict.keys())
    for i, entry in enumerate(entries):
        is_last = (i == len(entries) - 1)
        marker = "└── " if is_last else "├── "
        # 子要素がある(=dict)ならフォルダ、Noneならファイル
        if isinstance(tree_dict[entry], dict):
            # フォルダとして表示
            lines.append(prefix + marker + entry + "/")
            # 次の階層のプレフィックスを用意
            extension = "    " if is_last else "│   "
            sub_prefix = prefix + extension
            # 再帰的に生成
            lines.extend(format_tree(tree_dict[entry], sub_prefix))
        else:
            # ファイルとして表示
            lines.append(prefix + marker + entry)
    return lines


# =====================================
# ユーザー入力
# =====================================
repo_url = st.text_input("GitリポジトリURL (例: https://github.com/username/repo.git)")

st.subheader("スキャン対象拡張子")
available_exts = [".py", ".js", ".ts", ".sh", ".md", ".txt", ".java", ".cpp", ".json",".yaml",""]
chosen_exts = []
for ext in available_exts:
    default_checked = (ext in [".py", ".md"])  # デモ用に .py と .md を初期ON
    if st.checkbox(ext, key=f"ext_{ext}", value=default_checked):
        chosen_exts.append(ext)

# =====================================
# スキャン開始ボタン
# =====================================
if st.button("スキャン開始"):
    if not repo_url.strip():
        st.error("リポジトリURLを入力してください。")
    else:
        # 既にクローン済フォルダがあれば削除
        if st.session_state.cloned_repo_dir and Path(st.session_state.cloned_repo_dir).exists():
            shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True)
        
        # 一時フォルダを作成してクローン
        tmp_dir = tempfile.mkdtemp()
        clone_path = Path(tmp_dir) / "cloned_repo"

        try:
            st.write(f"リポジトリをクローン中: {clone_path}")
            git.Repo.clone_from(repo_url, clone_path)
            st.session_state.cloned_repo_dir = str(clone_path)
        except Exception as e:
            st.error(f"クローン失敗: {e}")
            st.session_state.cloned_repo_dir = None
            st.session_state.scanned_files = []
            st.stop()

        # スキャン
        scanner = FileScanner(base_dir=clone_path, target_extensions=set(chosen_exts))
        found_files = scanner.scan_files()

        st.session_state.scanned_files = found_files
        st.session_state.selected_files = set()

        st.success(f"スキャン完了: {len(found_files)}個のファイルを検出")

# =====================================
# クローン削除ボタン
# =====================================
if st.session_state.cloned_repo_dir:
    if st.button("クローン済みデータを削除"):
        shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True)
        st.session_state.cloned_repo_dir = None
        st.session_state.scanned_files = []
        st.session_state.selected_files = set()
        st.success("クローンしたディレクトリを削除しました")

# =====================================
# スキャン結果がある場合 → ツリー表示 + ファイル選択
# =====================================
if st.session_state.scanned_files:
    base_path = Path(st.session_state.cloned_repo_dir)

    # --- ツリーを作る ---
    # scanned_files は「指定拡張子」だけ取得されているので、そのファイルパスのみでツリーを構築
    rel_paths = [f.path.relative_to(base_path) for f in st.session_state.scanned_files]
    tree_dict = build_tree(rel_paths)
    tree_lines = format_tree(tree_dict)
    ascii_tree = "\n".join(tree_lines)

    st.write("## スキャン結果")
    col_tree, col_files = st.columns([1, 2])  # 左:ツリー, 右:ファイル一覧

    with col_tree:
        st.markdown("**ディレクトリ構造 (指定拡張子のみ)**")
        st.markdown(f"```\n{ascii_tree}\n```")

    with col_files:
        st.markdown("**ファイル一覧 (チェックボックス)**")

        col_btn1, col_btn2 = st.columns(2)
        with col_btn1:
            if st.button("すべて選択"):
                st.session_state.selected_files = set(rel_paths)
        with col_btn2:
            if st.button("すべて解除"):
                st.session_state.selected_files = set()

        for file_info in st.session_state.scanned_files:
            rel_path = file_info.path.relative_to(base_path)
            checked = rel_path in st.session_state.selected_files

            new_checked = st.checkbox(
                f"{rel_path} ({file_info.formatted_size})",
                value=checked,
                key=str(rel_path)  # keyの重複回避
            )
            if new_checked:
                st.session_state.selected_files.add(rel_path)
            else:
                st.session_state.selected_files.discard(rel_path)


# =====================================
# 選択ファイルをまとめてMarkdown化 & ダウンロード
# =====================================
def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str:
    output = []
    for f in files:
        rel_path = f.path.relative_to(base_dir)
        if rel_path in selected_paths:
            output.append(f"## {rel_path}")
            output.append("------------")
            if f.content is not None:
                output.append(f.content)
            else:
                output.append("# Failed to read content")
            output.append("")  # 空行
    return "\n".join(output)

if st.session_state.scanned_files:
    st.write("## 選択ファイルをダウンロード")
    if st.button("選択ファイルをMarkdownとしてダウンロード(整形後,下にダウンロードボタンが出ます)"):
        base_path = Path(st.session_state.cloned_repo_dir)
        markdown_text = create_markdown_for_selected(
            st.session_state.scanned_files,
            st.session_state.selected_files,
            base_path
        )
        st.download_button(
            label="Markdownダウンロード",
            data=markdown_text,
            file_name="selected_files.md",
            mime="text/markdown"
        )