from __future__ import annotations import argparse import json import sys from pathlib import Path from app.mailer.attachments.resolver import AttachmentResolutionReport, resolve_campaign_attachments from app.mailer.campaign.loader import CampaignLoadError, load_campaign_config from app.mailer.campaign.entries import EntryLoadError def _print_report(report: AttachmentResolutionReport, *, verbose: bool = False) -> None: print(f"Campaign: {report.campaign_name} ({report.campaign_id})") print(f"Campaign file: {report.campaign_file}") print(f"Attachments base path: {report.attachments_base_path}") print(f"Entries: {report.entries_count}") print( "Status: " f"ready={report.ready_count}, " f"warning={report.warning_count}, " f"needs_review={report.needs_review_count}, " f"blocked={report.blocked_count}, " f"excluded={report.excluded_count}, " f"inactive={report.inactive_count}" ) for entry in report.entries: print("---") label = entry.entry_id or f"#{entry.entry_index}" print(f"Entry {label}: {entry.status.value}, matches={entry.match_count}") for issue in entry.issues: behavior = f", behavior={issue.behavior.value}" if issue.behavior else "" print(f" [{issue.severity.value}] {issue.code}{behavior}: {issue.message}") if verbose: for attachment in entry.attachments: print( f" - {attachment.scope.value}[{attachment.index}] " f"{attachment.attachment_id or ''} " f"{attachment.status.value}: {attachment.directory}/{attachment.file_filter}" ) for match in attachment.matches: print(f" {match}") def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Resolve campaign attachment patterns and report missing/ambiguous matches.") parser.add_argument("--campaign", required=True, help="Path to campaign.json") parser.add_argument("--json", action="store_true", help="Output machine-readable JSON") parser.add_argument("--verbose", "-v", action="store_true", help="Print resolved configs and matched files") args = parser.parse_args(argv) campaign_path = Path(args.campaign) try: config = load_campaign_config(campaign_path) report = resolve_campaign_attachments(config, campaign_file=campaign_path) except (CampaignLoadError, EntryLoadError, ValueError) as exc: print(f"Error: {exc}", file=sys.stderr) return 2 if args.json: print(json.dumps(report.model_dump(mode="json"), ensure_ascii=False, indent=2)) else: _print_report(report, verbose=args.verbose) return 0 if __name__ == "__main__": raise SystemExit(main())