#!/usr/bin/env python3
import argparse
import json
import subprocess
from datetime import datetime, timezone
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
BACKLOG = ROOT / 'backlog' / 'features.json'
ARTIFACTS = ROOT / 'work' / 'artifacts'


def now_iso():
    return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace('+00:00', 'Z')


def run_git(*args, check=True):
    result = subprocess.run(
        ['git', *args],
        cwd=ROOT,
        text=True,
        capture_output=True,
    )
    if check and result.returncode != 0:
        msg = result.stderr.strip() or result.stdout.strip() or f'git command failed: {args}'
        raise SystemExit(msg)
    return result


def ensure_git_repo():
    result = run_git('rev-parse', '--is-inside-work-tree', check=False)
    if result.returncode != 0 or result.stdout.strip() != 'true':
        raise SystemExit('This project is not inside a git repository. Run git init or clone a repo first.')


def load_backlog():
    return json.loads(BACKLOG.read_text(encoding='utf-8'))


def find_feature(feature_id):
    data = load_backlog()
    for feature in data.get('features', []):
        if str(feature.get('id')) == feature_id:
            return feature
    raise SystemExit(f'Feature not found in backlog: {feature_id}')


def current_branch():
    branch = run_git('symbolic-ref', '--quiet', '--short', 'HEAD', check=False).stdout.strip()
    if not branch:
        branch = run_git('rev-parse', '--abbrev-ref', 'HEAD', check=False).stdout.strip()
    if not branch or branch == 'HEAD':
        raise SystemExit('Detached HEAD is not supported for publish. Checkout a branch first.')
    return branch


def ensure_remote(remote):
    remotes = [line.strip() for line in run_git('remote').stdout.splitlines() if line.strip()]
    if remote not in remotes:
        raise SystemExit(f'Remote not found: {remote}. Add it first with git remote add {remote} <url>.')


def status_porcelain():
    return run_git('status', '--porcelain').stdout.strip()


def default_commit_message(feature):
    feature_id = feature['id']
    ticket_type = feature.get('type')
    title = str(feature.get('title', '')).strip()
    if ticket_type:
        return f'{feature_id} {ticket_type}: {title}'
    return f'{feature_id}: {title}'


def write_publish_artifact(feature_id, payload):
    feature_dir = ARTIFACTS / feature_id
    feature_dir.mkdir(parents=True, exist_ok=True)
    path = feature_dir / 'publish.json'
    path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + '\n', encoding='utf-8')
    return path


def ensure_git_identity():
    name = run_git('config', 'user.name', check=False).stdout.strip()
    email = run_git('config', 'user.email', check=False).stdout.strip()
    if not name or not email:
        raise SystemExit('Missing git identity. Configure git user.name and user.email before publish.')


def main():
    parser = argparse.ArgumentParser(description='Commit and push one ticket, then write publish.json evidence.')
    parser.add_argument('--feature-id', required=True)
    parser.add_argument('--remote', default='origin')
    parser.add_argument('--branch', default='')
    parser.add_argument('--commit-message', default='')
    args = parser.parse_args()

    ensure_git_repo()
    ensure_git_identity()
    feature = find_feature(args.feature_id)
    remote = args.remote.strip() or 'origin'
    branch = args.branch.strip() or current_branch()
    ensure_remote(remote)

    if not status_porcelain():
        raise SystemExit('No git changes to publish. Nothing to commit.')

    commit_message = args.commit_message.strip() or default_commit_message(feature)
    payload = {
        'agent': 'leader',
        'verdict': 'PUBLISHED',
        'feature_id': args.feature_id,
        'branch': branch,
        'remote': remote,
        'message': commit_message,
        'pushed': True,
        'published_at': now_iso(),
        'note': 'This artifact is committed inside the publish commit for this ticket.'
    }
    artifact_path = write_publish_artifact(args.feature_id, payload)

    run_git('add', '-A')
    if not status_porcelain():
        raise SystemExit('No staged git changes after git add -A. Nothing to commit.')

    run_git('commit', '-m', commit_message)
    run_git('push', remote, branch)
    print(f'done -> {artifact_path}')


if __name__ == '__main__':
    main()
