#!/usr/bin/env python3
"""Update archive quantities from 3MF files.

This script updates the quantity field on existing archives by parsing
their 3MF files to count the number of printable objects.

Run this once after upgrading to add proper parts tracking to your projects.

Usage:
    # From the bambuddy directory:
    python scripts/update_archive_quantities.py

    # Or with docker:
    docker exec -it bambuddy python scripts/update_archive_quantities.py

    # Dry run (show what would be updated without changing anything):
    python scripts/update_archive_quantities.py --dry-run
"""

import argparse
import asyncio
import sys
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET

# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

from sqlalchemy import select

from backend.app.core.config import settings
from backend.app.core.database import async_session
from backend.app.models.archive import PrintArchive


def extract_object_count_from_3mf(file_path: Path) -> int | None:
    """Extract the number of printable objects from a 3MF file.

    Returns the count of non-skipped objects, or None if parsing fails.
    """
    try:
        with zipfile.ZipFile(file_path, "r") as zf:
            if "Metadata/slice_info.config" not in zf.namelist():
                return None

            content = zf.read("Metadata/slice_info.config").decode()
            root = ET.fromstring(content)

            # Find the plate (use first plate)
            plate = root.find(".//plate")
            if plate is None:
                return None

            # Count non-skipped objects
            count = 0
            for obj in plate.findall("object"):
                skipped = obj.get("skipped", "false")
                if skipped.lower() != "true":
                    count += 1

            return count if count > 0 else None

    except Exception as e:
        print(f"  Error parsing {file_path.name}: {e}")
        return None


async def update_archive_quantities(dry_run: bool = False):
    """Update quantity field on archives based on 3MF object count."""

    print("=" * 60)
    print("Archive Quantity Updater")
    print("=" * 60)
    print()

    if dry_run:
        print("DRY RUN MODE - No changes will be made")
        print()

    async with async_session() as db:
        # Get all archives with quantity=1 (the default)
        result = await db.execute(select(PrintArchive).where(PrintArchive.quantity == 1))
        archives = result.scalars().all()

        print(f"Found {len(archives)} archives with quantity=1")
        print()

        updated = 0
        skipped = 0
        errors = 0

        for archive in archives:
            # Skip if no file path
            if not archive.file_path:
                skipped += 1
                continue

            file_path = settings.base_dir / archive.file_path

            # Skip if file doesn't exist
            if not file_path.exists():
                print(f"  [{archive.id}] File not found: {archive.file_path}")
                skipped += 1
                continue

            # Extract object count
            object_count = extract_object_count_from_3mf(file_path)

            if object_count is None:
                skipped += 1
                continue

            if object_count == 1:
                # No change needed
                skipped += 1
                continue

            # Update the archive
            print(f"  [{archive.id}] {archive.print_name}: 1 -> {object_count} parts")

            if not dry_run:
                archive.quantity = object_count
                updated += 1
            else:
                updated += 1

        if not dry_run:
            await db.commit()

        print()
        print("-" * 60)
        print(f"Updated: {updated}")
        print(f"Skipped: {skipped} (no change needed or file not found)")
        print(f"Errors:  {errors}")
        print()

        if dry_run and updated > 0:
            print("Run without --dry-run to apply these changes.")


def main():
    parser = argparse.ArgumentParser(description="Update archive quantities from 3MF files")
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Show what would be updated without making changes",
    )
    args = parser.parse_args()

    asyncio.run(update_archive_quantities(dry_run=args.dry_run))


if __name__ == "__main__":
    main()
