"""Ingest a manually-exported iTunes/Music Library.xml into the DB.

The file is an Apple property list, so plistlib parses it natively. Upsert by
the iTunes persistent/numeric Track ID; skipped entirely if the file's mtime
hasn't changed since the last run.
"""
import logging
import os
import plistlib

from tqdm import tqdm

from Env import itunes_xml_path
from src.db.database import session_scope
from src.db.models import IngestState, SOURCE_ITUNES, Track
from src.match.normalize import norm_key

log = logging.getLogger("musicindexer.itunes")
_STATE_KEY = "itunes_xml_mtime"


def ingest_itunes(xml_path=None, force=False):
    xml_path = str(xml_path or itunes_xml_path)
    if not os.path.isfile(xml_path):
        log.warning("iTunes XML not found: %s — skipping", xml_path)
        return {"new": 0, "updated": 0, "skipped": True}

    mtime = str(os.path.getmtime(xml_path))
    with session_scope() as session:
        state = session.get(IngestState, _STATE_KEY)
        if state and state.value == mtime and not force:
            log.info("iTunes XML unchanged — skipping")
            return {"new": 0, "updated": 0, "skipped": True}

    with open(xml_path, "rb") as fh:
        plist = plistlib.load(fh)
    raw_tracks = plist.get("Tracks", {})

    counts = {"new": 0, "updated": 0, "skipped": False}
    with session_scope() as session:
        existing = {t.source_id: t for t in
                    session.query(Track).filter_by(source=SOURCE_ITUNES).all()}
        for tid, tr in tqdm(raw_tracks.items(), desc="ingest itunes", unit="track"):
            name = tr.get("Name")
            artist = tr.get("Artist") or tr.get("Album Artist")
            if not name:
                continue
            fields = dict(
                title=name, artist=artist, artists=artist, album=tr.get("Album"),
                duration_ms=tr.get("Total Time"), play_count=tr.get("Play Count") or 0,
                norm_key=norm_key(artist or "", name),
            )
            source_id = str(tid)
            track = existing.get(source_id)
            if track is None:
                session.add(Track(source=SOURCE_ITUNES, source_id=source_id, **fields))
                counts["new"] += 1
            else:
                for key, value in fields.items():
                    setattr(track, key, value)
                counts["updated"] += 1

        state = session.get(IngestState, _STATE_KEY) or IngestState(key=_STATE_KEY)
        state.value = mtime
        session.merge(state)

    log.info("itunes: %(new)d new, %(updated)d updated", counts)
    return counts
