"""
watchdog_process.py — Kører som selvstændig subprocess.
Overvåger musikmapper og opdaterer SQLite ved fil-ændringer.

Start: python watchdog_process.py <db_path>
"""
import sys
import os
import time
import json
import sqlite3
import logging
from pathlib import Path

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [watchdog] %(message)s",
    stream=sys.stderr
)
logger = logging.getLogger(__name__)

SUPPORTED = {'.mp3', '.flac', '.m4a', '.ogg', '.wav', '.aiff', '.wma'}


def is_supported(path: Path) -> bool:
    return path.suffix.lower() in SUPPORTED


def get_libraries(db_path: str) -> list[dict]:
    try:
        conn = sqlite3.connect(db_path)
        conn.row_factory = sqlite3.Row
        libs = conn.execute(
            "SELECT id, path FROM libraries WHERE is_active=1"
        ).fetchall()
        conn.close()
        return [dict(l) for l in libs]
    except Exception:
        return []


def process_file(db_path: str, library_id: int, file_path: str,
                 deleted: bool = False):
    """Opdater SQLite for én fil."""
    try:
        # Tilføj app-mappen til sys.path så tag_reader kan importeres
        app_dir = str(Path(__file__).parent.parent)
        if app_dir not in sys.path:
            sys.path.insert(0, app_dir)

        conn = sqlite3.connect(db_path)
        conn.row_factory = sqlite3.Row

        if deleted:
            conn.execute(
                "UPDATE songs SET file_missing=1 WHERE local_path=?",
                (file_path,)
            )
            conn.commit()
            conn.close()
            return

        from local.tag_reader import read_tags
        import uuid

        mtime = str(os.path.getmtime(file_path))
        tags  = read_tags(Path(file_path))
        extra = json.dumps(tags.get("extra_tags", {}), ensure_ascii=False)

        existing = conn.execute(
            "SELECT id, bpm FROM songs WHERE local_path=?", (file_path,)
        ).fetchone()

        if existing:
            bpm = tags.get("bpm", 0) or existing["bpm"] or 0
            conn.execute("""
                UPDATE songs SET
                    library_id=?, title=?, artist=?, album=?,
                    bpm=?, duration_sec=?, file_format=?,
                    file_modified_at=?, file_missing=0, extra_tags=?
                WHERE id=?
            """, (library_id, tags.get("title",""), tags.get("artist",""),
                  tags.get("album",""), bpm, tags.get("duration_sec",0),
                  tags.get("file_format",""), mtime, extra, existing["id"]))
        else:
            conn.execute("""
                INSERT OR IGNORE INTO songs
                    (id, library_id, local_path, title, artist, album,
                     bpm, duration_sec, file_format, file_modified_at, extra_tags)
                VALUES (?,?,?,?,?,?,?,?,?,?,?)
            """, (str(uuid.uuid4()), library_id, file_path,
                  tags.get("title",""), tags.get("artist",""),
                  tags.get("album",""), tags.get("bpm",0),
                  tags.get("duration_sec",0), tags.get("file_format",""),
                  mtime, extra))

        conn.commit()
        conn.close()
        logger.info(f"Opdateret: {Path(file_path).name}")
    except Exception as e:
        logger.error(f"Fejl ved {file_path}: {e}")


def run(db_path: str):
    try:
        from watchdog.observers.polling import PollingObserver
        from watchdog.events import FileSystemEventHandler
    except ImportError:
        logger.error("watchdog ikke installeret")
        sys.exit(1)

    class Handler(FileSystemEventHandler):
        def __init__(self, library_id: int):
            self.library_id = library_id

        def on_created(self, event):
            if not event.is_directory and is_supported(Path(event.src_path)):
                time.sleep(0.5)  # Vent til filen er skrevet færdig
                process_file(db_path, self.library_id, event.src_path)

        def on_modified(self, event):
            if not event.is_directory and is_supported(Path(event.src_path)):
                process_file(db_path, self.library_id, event.src_path)

        def on_deleted(self, event):
            if not event.is_directory and is_supported(Path(event.src_path)):
                process_file(db_path, self.library_id, event.src_path,
                             deleted=True)

        def on_moved(self, event):
            if not event.is_directory:
                if is_supported(Path(event.src_path)):
                    process_file(db_path, self.library_id, event.src_path,
                                 deleted=True)
                if is_supported(Path(event.dest_path)):
                    process_file(db_path, self.library_id, event.dest_path)

    # Brug 60 sekunders poll-interval — opdager ændringer inden for 1 minut
    observer = PollingObserver(timeout=60)

    libraries = get_libraries(db_path)
    if not libraries:
        logger.info("Ingen biblioteker — venter...")

    for lib in libraries:
        path = Path(lib["path"])
        if path.exists():
            observer.schedule(Handler(lib["id"]), str(path), recursive=True)
            logger.info(f"Overvåger: {path}")
        else:
            logger.warning(f"Mappe ikke fundet: {path}")

    observer.start()
    logger.info("Watchdog kører")

    try:
        while True:
            time.sleep(30)
            # Tjek om der er kommet nye biblioteker siden start
            current = get_libraries(db_path)
            current_paths = {lib["path"] for lib in current}
            watched_paths = {str(w.path) for w in observer.emitters}
            for lib in current:
                if lib["path"] not in watched_paths:
                    path = Path(lib["path"])
                    if path.exists():
                        observer.schedule(
                            Handler(lib["id"]), str(path), recursive=True
                        )
                        logger.info(f"Tilføjet overvågning: {path}")
    except KeyboardInterrupt:
        pass
    finally:
        observer.stop()
        observer.join()
        logger.info("Watchdog stoppet")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Brug: python watchdog_process.py <db_path>")
        sys.exit(1)
    run(sys.argv[1])
