"""Google Photos Takeout importer for Muleline."""
from __future__ import annotations

import json
import mimetypes
import os
import time
import zipfile
from pathlib import Path

from muleline.db import get_db
from muleline.exif import extract_metadata
from muleline.hasher import sha256


SUPPORTED_MIMES = {
    "image/jpeg", "image/png", "image/gif", "image/webp", "image/heic", "image/heif",
    "image/bmp", "image/tiff", "image/svg+xml",
    "video/mp4", "video/quicktime", "video/x-msvideo", "video/webm", "video/3gpp",
    "video/x-matroska",
}


def import_takeout_zip(zip_path: str | Path, owner_id: str, storage) -> dict:
    """Import a Google Photos Takeout ZIP into Muleline.

    Google Takeout structure:
        Takeout/Google Photos/<album-or-date>/
            photo.jpg
            photo.jpg.json  (metadata sidecar)

    Returns dict with counts: imported, skipped_duplicate, skipped_unsupported, errors.
    """
    zip_path = Path(zip_path)
    if not zip_path.exists():
        return {"error": "ZIP file not found"}

    stats = {"imported": 0, "skipped_duplicate": 0, "skipped_unsupported": 0, "errors": 0}
    conn = get_db()

    try:
        with zipfile.ZipFile(str(zip_path), "r") as zf:
            # Build map of sidecar JSON files
            sidecars = {}
            for name in zf.namelist():
                if name.endswith(".json") and not name.endswith("metadata.json"):
                    base = name[:-5]  # Remove .json
                    sidecars[base] = name

            for name in zf.namelist():
                if name.endswith("/") or name.endswith(".json"):
                    continue

                mime, _ = mimetypes.guess_type(name)
                if not mime or mime not in SUPPORTED_MIMES:
                    stats["skipped_unsupported"] += 1
                    continue

                try:
                    data = zf.read(name)
                except Exception:
                    stats["errors"] += 1
                    continue

                file_hash = sha256(data)

                # Check for duplicate
                existing = conn.execute(
                    "SELECT id FROM files WHERE file_hash = ? AND owner_id = ?",
                    (file_hash, owner_id),
                ).fetchone()
                if existing:
                    stats["skipped_duplicate"] += 1
                    continue

                original_name = os.path.basename(name)
                filename = f"{int(time.time())}_{original_name}"
                storage_key = storage.write(filename, data)

                # Extract EXIF from the file data
                meta = extract_metadata(data)

                # Try to get Google's metadata from sidecar JSON
                sidecar_name = sidecars.get(name)
                google_meta = {}
                if sidecar_name:
                    try:
                        google_meta = json.loads(zf.read(sidecar_name))
                    except Exception:
                        pass

                # Merge: Google timestamp > EXIF timestamp
                date_taken = meta.get("date_taken")
                if not date_taken and google_meta.get("photoTakenTime", {}).get("timestamp"):
                    date_taken = float(google_meta["photoTakenTime"]["timestamp"])

                gps_lat = meta.get("gps_lat")
                gps_lon = meta.get("gps_lon")
                if not gps_lat and google_meta.get("geoData", {}).get("latitude"):
                    geo = google_meta["geoData"]
                    if geo["latitude"] != 0.0 or geo["longitude"] != 0.0:
                        gps_lat = geo["latitude"]
                        gps_lon = geo["longitude"]

                now = time.time()
                conn.execute(
                    """INSERT INTO files
                       (owner_id, filename, original_name, mime_type, file_size, file_hash,
                        storage_key, date_taken, gps_lat, gps_lon, width, height, created_at, updated_at)
                       VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
                    (
                        owner_id, filename, original_name, mime,
                        len(data), file_hash, storage_key,
                        date_taken, gps_lat, gps_lon,
                        meta.get("width"), meta.get("height"),
                        now, now,
                    ),
                )
                stats["imported"] += 1

                # Commit every 50 files for safety
                if stats["imported"] % 50 == 0:
                    conn.commit()

        conn.commit()
    except zipfile.BadZipFile:
        return {"error": "Invalid ZIP file"}
    finally:
        conn.close()

    return stats
