"""
camera.py — pytapo interaction: event polling + SD card clip download.

Tapo cameras use a LOCAL password (set in the camera's settings), NOT the
Tapo cloud account password. See README for how to find/set it.
"""

import asyncio
import logging
import os
import sqlite3
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any

from pytapo import Tapo

logger = logging.getLogger(__name__)


@dataclass
class TapoEvent:
    camera_name: str
    camera_ip: str
    event_id: str
    event_type: str       # "motion", "person", "vehicle", etc.
    start_time: datetime
    end_time: datetime | None
    raw: dict[str, Any]


class EventStore:
    """SQLite-backed deduplication store for processed events."""

    def __init__(self, db_path: str):
        self._db_path = db_path
        self._init_db()

    def _init_db(self):
        with self._conn() as conn:
            conn.execute(
                """
                CREATE TABLE IF NOT EXISTS processed_events (
                    event_id TEXT PRIMARY KEY,
                    camera_name TEXT,
                    processed_at TEXT
                )
                """
            )

    def _conn(self) -> sqlite3.Connection:
        return sqlite3.connect(self._db_path)

    def is_seen(self, event_id: str) -> bool:
        with self._conn() as conn:
            row = conn.execute(
                "SELECT 1 FROM processed_events WHERE event_id = ?", (event_id,)
            ).fetchone()
        return row is not None

    def mark_seen(self, event_id: str, camera_name: str):
        with self._conn() as conn:
            conn.execute(
                "INSERT OR IGNORE INTO processed_events (event_id, camera_name, processed_at) VALUES (?, ?, ?)",
                (event_id, camera_name, datetime.utcnow().isoformat()),
            )

    def cleanup_old(self, keep_days: int = 7):
        """Remove events older than keep_days to avoid DB bloat."""
        with self._conn() as conn:
            conn.execute(
                "DELETE FROM processed_events WHERE processed_at < datetime('now', ?)",
                (f"-{keep_days} days",),
            )


class CameraClient:
    """Wraps pytapo for a single camera."""

    def __init__(self, name: str, ip: str, password: str, username: str = "admin"):
        self.name = name
        self.ip = ip
        self._username = username
        self._password = password
        self._tapo: Tapo | None = None

    def _connect(self) -> Tapo:
        if self._tapo is None:
            logger.debug("Connecting to camera %s (%s)", self.name, self.ip)
            self._tapo = Tapo(self.ip, self._username, self._password, self._password)
        return self._tapo

    def _reconnect(self) -> Tapo:
        self._tapo = None
        return self._connect()

    def get_events(self, start_index: int = 0, count: int = 20) -> list[dict]:
        """Fetch recent detection events from the camera."""
        try:
            tapo = self._connect()
            result = tapo.getRecordings(start_index, count)
            return result if isinstance(result, list) else []
        except Exception as exc:
            logger.warning("Failed to get events from %s: %s", self.name, exc)
            self._tapo = None
            return []

    def download_clip(self, recording: dict, dest_path: str) -> bool:
        """
        Download a recording file from the SD card to dest_path.
        Returns True on success.
        """
        try:
            tapo = self._connect()
            # pytapo's downloadRecording writes the file
            # The recording dict contains 'startTime' and file info
            file_url = recording.get("uri") or recording.get("url") or recording.get("key")
            if not file_url:
                logger.warning("No URI found in recording: %s", recording)
                return False

            tapo.downloadRecording(file_url, dest_path)
            logger.info("Downloaded clip to %s", dest_path)
            return True
        except Exception as exc:
            logger.error("Download failed for %s: %s", self.name, exc)
            self._tapo = None
            return False


def parse_events(camera_name: str, camera_ip: str, raw_list: list[dict]) -> list[TapoEvent]:
    """Convert raw pytapo recording dicts to TapoEvent objects."""
    events = []
    for item in raw_list:
        try:
            # pytapo returns timestamps as unix seconds (int or str)
            start_ts = int(item.get("startTime") or item.get("start_time", 0))
            end_ts = item.get("endTime") or item.get("end_time")
            start_dt = datetime.utcfromtimestamp(start_ts) if start_ts else datetime.utcnow()
            end_dt = datetime.utcfromtimestamp(int(end_ts)) if end_ts else None

            # Event type: pytapo may use "eventType" or nested "detectionType"
            evt_type = (
                item.get("eventType")
                or item.get("detectionType")
                or item.get("event_type")
                or "motion"
            )
            if isinstance(evt_type, list):
                evt_type = evt_type[0] if evt_type else "motion"

            # Unique ID: prefer explicit id, fallback to start timestamp + camera
            event_id = (
                item.get("id")
                or item.get("eventId")
                or f"{camera_ip}_{start_ts}"
            )

            events.append(
                TapoEvent(
                    camera_name=camera_name,
                    camera_ip=camera_ip,
                    event_id=str(event_id),
                    event_type=str(evt_type),
                    start_time=start_dt,
                    end_time=end_dt,
                    raw=item,
                )
            )
        except Exception as exc:
            logger.warning("Failed to parse event item %s: %s", item, exc)
    return events
