#!/usr/bin/env python3
"""
atlaslatex_new.py — Python equivalent of the 'make new*' targets in the
ATLAS LaTeX Makefile, plus a (stub) update command.

Usage:
    python atlaslatex_new.py [--basename NAME] [--texmf] <command>

Commands:
    newnote          Create a new ATLAS note (default)
    newpaper         Create a new ATLAS paper / CONF / PUB Note draft
    newbook          Create a new long document (e.g. TDR)
    draftcover       Copy the draft-cover template
    preprintcover    Copy the preprint-cover template
    newdata          Create HepData material files
    update           Update atlaslatex (not yet implemented)
    help             Show this help message

Options:
    --basename NAME  Base filename for the new document (default: mydocument)
    --texmf          Use templates suitable for a central texmf installation
"""

import argparse
import re
import shutil
import sys
from pathlib import Path

# ---------------------------------------------------------------------------
# Defaults (mirror Makefile variables)
# ---------------------------------------------------------------------------
DEFAULT_BASENAME  = 'mydocument'
TEMPLATE_DIR      = Path('template')

# ---------------------------------------------------------------------------
# Low-level helpers
# ---------------------------------------------------------------------------

def sed_replace(src: Path, dst: Path, old: str, new: str,
                extra_subs: list[tuple[str, str]] | None = None) -> None:
    """Read *src*, replace *old* -> *new* (and any *extra_subs*), write *dst*."""
    text = src.read_text(encoding='utf-8')
    text = text.replace(old, new)
    for pattern, replacement in (extra_subs or []):
        text = re.sub(pattern, replacement, text)
    dst.write_text(text, encoding='utf-8')
    print(f'  created  {dst}  (from {src})')


def cp(src: Path, dst: Path) -> None:
    shutil.copy(src, dst)
    print(f'  copied   {dst}  (from {src})')


def touch(path: Path) -> None:
    path.touch()
    print(f'  touched  {path}')


def write_file(path: Path, content: str) -> None:
    path.write_text(content, encoding='utf-8')
    print(f'  wrote    {path}')


def require_template(name: str) -> Path:
    path = TEMPLATE_DIR / name
    if not path.exists():
        sys.exit(f'Error: template file not found: {path}')
    return path


# ---------------------------------------------------------------------------
# Sub-targets (mirror Makefile phony targets)
# ---------------------------------------------------------------------------

def new_document(basename: str, template: str) -> None:
    """sed s/atlas-document/<basename>/ template/<template>.tex > <basename>.tex"""
    src = require_template(f'{template}.tex')
    dst = Path(f'{basename}.tex')
    sed_replace(src, dst, 'atlas-document', basename)


def new_document_texmf(basename: str, template: str) -> None:
    """Like new_document but also comments out the atlaslatexpath RequirePackage line."""
    src = require_template(f'{template}.tex')
    dst = Path(f'{basename}.tex')
    sed_replace(
        src, dst,
        'atlas-document', basename,
        extra_subs=[(
            r'\\RequirePackage\{latex/atlaslatexpath\}',
            r'% \\RequirePackage{latex/atlaslatexpath}',
        )],
    )


def new_paper_metadata(basename: str) -> None:
    cp(require_template('atlas-paper-metadata.tex'), Path(f'{basename}-metadata.tex'))


def new_note_metadata(basename: str) -> None:
    cp(require_template('atlas-note-metadata.tex'), Path(f'{basename}-metadata.tex'))


def new_files(basename: str) -> None:
    write_file(Path(f'{basename}.bib'),
               '% Put your own bibliography entries in this file.\n')
    touch(Path(f'{basename}-defs.sty'))


def new_auxmat(basename: str) -> None:
    cp(require_template('atlas-auxmat.tex'),  Path(f'{basename}-auxmat.tex'))
    cp(require_template('atlas-hepdata.tex'), Path(f'{basename}-hepdata.tex'))


# ---------------------------------------------------------------------------
# Top-level commands (mirror Makefile's public targets)
# ---------------------------------------------------------------------------

def cmd_newnote(basename: str, texmf: bool = False) -> None:
    """atlas-note template — ATLAS note (default)."""
    print(f'Creating new ATLAS note: {basename}')
    if texmf:
        new_document_texmf(basename, 'atlas-note')
    else:
        new_document(basename, 'atlas-note')
    new_files(basename)
    new_note_metadata(basename)


def cmd_newpaper(basename: str, texmf: bool = False) -> None:
    """atlas-paper template — paper / CONF Note / PUB Note."""
    print(f'Creating new ATLAS paper: {basename}')
    if texmf:
        new_document_texmf(basename, 'atlas-paper')
    else:
        new_document(basename, 'atlas-paper')
    new_files(basename)
    new_paper_metadata(basename)
    new_auxmat(basename)


def cmd_newbook(basename: str, texmf: bool = False) -> None:
    """atlas-book template — long document (TDR etc.)."""
    print(f'Creating new ATLAS book: {basename}')
    if texmf:
        new_document_texmf(basename, 'atlas-book')
    else:
        new_document(basename, 'atlas-book')
    new_files(basename)
    new_paper_metadata(basename)


def cmd_draftcover(basename: str, texmf: bool = False) -> None:
    """Copy the draft-cover template."""
    print(f'Creating draft cover: {basename}-draft-cover.tex')
    cp(require_template('atlas-draft-cover.tex'),
       Path(f'{basename}-draft-cover.tex'))


def cmd_preprintcover(basename: str, texmf: bool = False) -> None:
    """Copy the preprint-cover template."""
    print(f'Creating preprint cover: {basename}-preprint-cover.tex')
    cp(require_template('atlas-preprint-cover.tex'),
       Path(f'{basename}-preprint-cover.tex'))


def cmd_newdata(basename: str, texmf: bool = False) -> None:
    """Create HepData material files."""
    print(f'Creating HepData files for: {basename}')
    src = require_template('atlas-hepdata-main.tex')
    sed_replace(src, Path(f'{basename}-hepdata-main.tex'),
                'atlas-document', basename)
    cp(require_template('atlas-hepdata.tex'), Path(f'{basename}-hepdata.tex'))


def cmd_update(basename: str) -> None:  # noqa: ARG001
    """Update atlaslatex — not yet implemented."""
    print('update: not yet implemented.')
    # TODO: add update logic here, e.g.:
    #   - pull latest atlaslatex release from GitLab/CERN
    #   - replace latex/ and template/ subdirectories
    #   - report version changes


def cmd_help(_basename: str) -> None:
    print(__doc__)


# ---------------------------------------------------------------------------
# Command dispatch table
# ---------------------------------------------------------------------------

COMMANDS: dict[str, tuple[callable, str]] = {
    'newnote':       (cmd_newnote,       'Create a new ATLAS note (default)'),
    'newpaper':      (cmd_newpaper,      'Create a new paper / CONF / PUB Note draft'),
    'newbook':       (cmd_newbook,       'Create a new long document (e.g. TDR)'),
    'draftcover':    (cmd_draftcover,    'Copy the draft-cover template'),
    'preprintcover': (cmd_preprintcover, 'Copy the preprint-cover template'),
    'newdata':       (cmd_newdata,       'Create HepData material files'),
    'update':        (cmd_update,        'Update atlaslatex (stub — not yet implemented)'),
    'help':          (cmd_help,          'Show this help message'),
}

# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------

def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description="Python equivalent of the ATLAS LaTeX Makefile 'new*' targets.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='\n'.join(
            f'  {name:<16} {desc}' for name, (_, desc) in COMMANDS.items()
        ),
    )
    parser.add_argument(
        '--basename', '-b',
        default=DEFAULT_BASENAME,
        metavar='NAME',
        help=f'Base filename for the new document (default: {DEFAULT_BASENAME})',
    )
    parser.add_argument(
        '--texmf',
         action='store_true',
         help='Use templates suitable for a central texmf installation',
    )
    parser.add_argument(
        'command',
        nargs='?',
        default='',
        choices=COMMANDS.keys(),
        metavar='COMMAND',
        help='Command to run',
    )
    return parser


def main() -> None:
    parser = build_parser()
    args = parser.parse_args()

    # A command must be given.
    if not args.command:
        parser.print_help()
        sys.exit(1)
    
    fn, _ = COMMANDS[args.command]
    fn(args.basename, args.texmf)


if __name__ == '__main__':
    main()
