#!/usr/bin/env python3
"""Semantic version helper for MercadoDeVida.

Source of truth: project/VERSION.
Mirrors the version into package.json files that are part of project/.
"""
from __future__ import annotations

import argparse
import json
import re
import subprocess
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
VERSION_FILE = ROOT / 'project' / 'VERSION'
PACKAGE_FILES = [
    ROOT / 'project' / 'package.json',
    ROOT / 'project' / 'apps' / 'admin' / 'package.json',
    ROOT / 'project' / 'apps' / 'pos' / 'package.json',
    ROOT / 'project' / 'frontend' / 'package.json',
    ROOT / 'project' / 'storefront' / 'package.json',
]
PACKAGE_LOCK_FILES = [
    ROOT / 'project' / 'package-lock.json',
    ROOT / 'project' / 'apps' / 'admin' / 'package-lock.json',
    ROOT / 'project' / 'apps' / 'pos' / 'package-lock.json',
    ROOT / 'project' / 'frontend' / 'package-lock.json',
    ROOT / 'project' / 'storefront' / 'package-lock.json',
]
SEMVER_RE = re.compile(r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:[-+][0-9A-Za-z.-]+)?$')


def read_version() -> str:
    version = VERSION_FILE.read_text(encoding='utf-8').strip()
    if not SEMVER_RE.match(version):
        raise SystemExit(f'[FAIL] Invalid semver in {VERSION_FILE}: {version}')
    return version


def write_version(version: str) -> None:
    if not SEMVER_RE.match(version):
        raise SystemExit(f'[FAIL] Invalid semver: {version}')
    VERSION_FILE.write_text(version + '\n', encoding='utf-8')
    for path in PACKAGE_FILES:
        if not path.exists():
            continue
        data = json.loads(path.read_text(encoding='utf-8'))
        data['version'] = version
        path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n', encoding='utf-8')
    for path in PACKAGE_LOCK_FILES:
        if not path.exists():
            continue
        data = json.loads(path.read_text(encoding='utf-8'))
        if 'version' in data:
            data['version'] = version
        root_package = data.get('packages', {}).get('')
        if isinstance(root_package, dict) and 'version' in root_package:
            root_package['version'] = version
        path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n', encoding='utf-8')


def bump(version: str, part: str) -> str:
    major, minor, patch = [int(p) for p in version.split('-', 1)[0].split('+', 1)[0].split('.')]
    if part == 'major':
        return f'{major + 1}.0.0'
    if part == 'minor':
        return f'{major}.{minor + 1}.0'
    if part == 'patch':
        return f'{major}.{minor}.{patch + 1}'
    raise SystemExit(f'[FAIL] Unsupported bump part: {part}')


def run(cmd: list[str]) -> None:
    subprocess.run(cmd, cwd=ROOT, check=True)


def main() -> int:
    parser = argparse.ArgumentParser(description='Manage project semantic version')
    sub = parser.add_subparsers(dest='command', required=True)

    sub.add_parser('show', help='print current version')

    bump_parser = sub.add_parser('bump', help='bump semantic version')
    bump_parser.add_argument('part', choices=['major', 'minor', 'patch'])
    bump_parser.add_argument('--commit', action='store_true', help='create conventional release commit')
    bump_parser.add_argument('--tag', action='store_true', help='create git tag vX.Y.Z (requires --commit or clean index)')

    set_parser = sub.add_parser('set', help='set exact semantic version')
    set_parser.add_argument('version')

    args = parser.parse_args()
    current = read_version()

    if args.command == 'show':
        print(current)
        return 0

    if args.command == 'set':
        write_version(args.version)
        print(f'[OK] Version set: {current} -> {args.version}')
        return 0

    next_version = bump(current, args.part)
    write_version(next_version)
    print(f'[OK] Version bumped: {current} -> {next_version}')

    if args.commit:
        msg = f'chore(release): v{next_version}'
        run(['python3', 'scripts/validate_conventional_commit.py', '--message', msg])
        run([
            'git',
            'add',
            'project/VERSION',
            *[str(p.relative_to(ROOT)) for p in PACKAGE_FILES if p.exists()],
            *[str(p.relative_to(ROOT)) for p in PACKAGE_LOCK_FILES if p.exists()],
        ])
        run(['git', 'commit', '-m', msg])

    if args.tag:
        run(['git', 'tag', f'v{next_version}'])
        print(f'[OK] Tagged v{next_version}')

    return 0


if __name__ == '__main__':
    raise SystemExit(main())
