import subprocess
from pathlib import Path
from typing import List, Tuple, Dict
from datetime import date


def get_commits_since_last_tag(project_dir: Path) -> List[Tuple[str, str]]:
    try:
        # 获取上一个标签
        tag_result = subprocess.run(
            ['git', 'describe', '--tags', '--abbrev=0'],
            cwd=project_dir,
            capture_output=True,
            text=True,
            check=False
        )
        if tag_result.returncode == 0:
            last_tag = tag_result.stdout.strip()
            range_spec = f"{last_tag}..HEAD"
        else:
            range_spec = "HEAD"
        result = subprocess.run(
            ['git', 'log', range_spec, '--pretty=format:%s|%b'],
            cwd=project_dir,
            capture_output=True,
            text=True,
            check=True
        )
        lines = result.stdout.strip().splitlines()
        commits = []
        for line in lines:
            if '|' in line:
                subject, body = line.split('|', 1)
            else:
                subject, body = line, ''
            commits.append((subject, body))
        return commits
    except (subprocess.CalledProcessError, FileNotFoundError):
        return []


def categorize_commit(subject: str, body: str) -> str:
    subject_lower = subject.lower()
    if subject_lower.startswith('feat'):
        return 'Added'
    elif subject_lower.startswith('fix'):
        return 'Fixed'
    elif subject_lower.startswith('docs'):
        return 'Documentation'
    elif subject_lower.startswith('style'):
        return 'Changed'
    elif subject_lower.startswith('refactor'):
        return 'Changed'
    elif subject_lower.startswith('perf'):
        return 'Changed'
    elif subject_lower.startswith('test'):
        return 'Changed'
    elif subject_lower.startswith('chore'):
        return 'Changed'
    else:
        return 'Changed'


def generate_changelog(project_dir: Path, new_version: str) -> None:
    commits = get_commits_since_last_tag(project_dir)
    if not commits:
        print("ℹ️ 没有新的提交，不生成 CHANGELOG。")
        return

    sections: Dict[str, List[str]] = {
        'Added': [],
        'Changed': [],
        'Fixed': [],
        'Documentation': [],
        'Removed': [],
        'Deprecated': [],
        'Security': []
    }

    for subject, body in commits:
        category = categorize_commit(subject, body)
        clean_subject = subject.split(':', 1)[-1].strip()
        sections[category].append(f"- {clean_subject}")

    today = date.today().isoformat()
    version_header = f"## [{new_version}] - {today}\n"

    content = version_header
    for section, items in sections.items():
        if items:
            content += f"\n### {section}\n"
            content += "\n".join(items) + "\n"

    changelog_path = project_dir / 'CHANGELOG.md'
    if changelog_path.exists():
        with open(changelog_path, 'r', encoding='utf-8') as f:
            old_content = f.read()
        new_full_content = content + "\n" + old_content
    else:
        header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n"
        new_full_content = header + content

    with open(changelog_path, 'w', encoding='utf-8') as f:
        f.write(new_full_content)

    print(f"✅ CHANGELOG.md 已更新。")