#!/usr/bin/env python3
import json
import os
import subprocess
import sys
from pathlib import Path


def run_git_command(command):
    """Run a git command and return the output."""
    try:
        result = subprocess.run(
            command, shell=True, capture_output=True, text=True, check=True
        )
        return result.stdout.strip()
    except subprocess.CalledProcessError as e:
        print(f"Error running git command: {command}")
        print(f"Error: {e.stderr}")
        sys.exit(1)


def get_commit_body(commit_hash):
    """Get the first line of the commit body for a given commit hash."""
    try:
        command = f'git log -1 --pretty=format:"%B" {commit_hash}'
        output = run_git_command(command)
        lines = output.split('\n')
        if len(lines) > 1:
            # Get everything after the first line (subject) and find first non-empty line
            body_lines = [line.strip() for line in lines[1:] if line.strip()]
            if body_lines:
                # Take first non-empty line and remove all line breaks
                first_line = body_lines[0].replace('\n', ' ').replace('\r', ' ')
                return first_line if first_line else None
        return None
    except:
        return None


def is_merge_commit(commit_hash):
    """Check if a commit is a merge commit."""
    try:
        command = f'git cat-file -p {commit_hash}'
        output = run_git_command(command)
        parent_count = output.count('parent ')
        return parent_count > 1
    except:
        return False


def get_commit_info(commit_range, repo_url):
    """Get commit information for a given range."""
    command = f'git log --pretty=format:"%h|%s|%H" {commit_range} --invert-grep --grep="^Merged in "'
    output = run_git_command(command)
    
    commits = []
    if output:
        for line in output.split('\n'):
            if line.strip():
                parts = line.split('|', 2)
                if len(parts) == 3:
                    hash_short, message, hash_full = parts
                    commit_data = {
                        "hash": hash_short,
                        "message": message,
                        "url": f"{repo_url}{hash_full}"
                    }
                    
                    # If it's a merge commit, get the full description
                    if is_merge_commit(hash_full):
                        body = get_commit_body(hash_full)
                        if body:
                            commit_data["description"] = body
                    
                    commits.append(commit_data)
    
    return commits


def main():
    # Get current directory and project root
    cur_dir = Path(__file__).parent.absolute()
    project_root = cur_dir / "../.."
    project_root = project_root.resolve()
    
    # Set up paths and URLs
    output_json_file = cur_dir / "../../docs/changelog/commit_changelog.json"
    output_txt_file = cur_dir / "../../docs/changelog/commit_changelog.txt"
    repo_url = "https://github.com/globaldigitalagency/autoadmin-library/commit/"
    
    # Fetch the latest remote tags and refs
    print("Fetching latest tags and refs...")
    run_git_command("git fetch --tags origin")
    
    # Detect the default branch dynamically
    default_branch_output = run_git_command("git remote show origin")
    default_branch = None
    for line in default_branch_output.split('\n'):
        if 'HEAD branch' in line:
            default_branch = line.split()[-1]
            break
    
    if not default_branch:
        print("Could not detect default branch")
        sys.exit(1)
    
    # Get tags sorted by version
    tags_output = run_git_command("git tag --sort=-v:refname")
    tags = tags_output.split('\n') if tags_output else []
    
    releases = []
    previous_tag = None
    
    # Process each tag
    for current_tag in tags:
        if current_tag.strip():
            if previous_tag:
                commits = get_commit_info(f"{current_tag}..{previous_tag}", repo_url)
                releases.append({
                    "tag": previous_tag,
                    "commits": commits
                })
            previous_tag = current_tag.strip()
    
    # Include commits between the latest tag and the remote default branch
    if previous_tag:
        commits = get_commit_info(f"{previous_tag}..origin/{default_branch}", repo_url)
        releases.append({
            "tag": f"{default_branch}-after-{previous_tag}",
            "commits": commits
        })
    
    # Create final JSON structure
    changelog_data = {
        "repository": repo_url,
        "default_branch": default_branch,
        "releases": releases
    }
    
    # Write JSON file
    output_json_file.parent.mkdir(parents=True, exist_ok=True)
    with open(output_json_file, 'w') as f:
        json.dump(changelog_data, f, indent=2)
    
    # Write text file
    with open(output_txt_file, 'w') as f:
        for release in releases:
            f.write(f"# Commits in {release['tag']}\n")
            for commit in release['commits']:
                if 'description' in commit:
                    f.write(f"{commit['hash']} {commit['message']} - {commit['description']} // {commit['url']}\n")
                else:
                    f.write(f"{commit['hash']} {commit['message']} // {commit['url']}\n")
            f.write("\n")
    
    # Express paths relative to project root
    json_relative = output_json_file.resolve().relative_to(project_root)
    txt_relative = output_txt_file.resolve().relative_to(project_root)
    
    print(f"Commit messages have been saved to:")
    print(f"  JSON: {json_relative}")
    print(f"  Text: {txt_relative}")


if __name__ == "__main__":
    main()