"""Tectra SDK Client — sign, verify, and watch content with local signing."""
import os
import logging
from pathlib import Path

import httpx

from tectravision_sdk.signer import (
    sign_image_locally, decrypt_private_key,
    compute_sha256, compute_perceptual_hash,
)

logger = logging.getLogger("tectravision_sdk")


class TectraClient:
    """Main SDK client for interacting with the Tectra platform.

    Signs locally using your org's private key. Only hashes/metadata
    are sent to the Tectra backend — image bytes never leave your infrastructure.
    """

    def __init__(
        self,
        api_key: str,
        signing_key_id: str,
        api_url: str = "http://localhost:8787",
        fernet_key: str | None = None,
    ):
        self.api_key = api_key
        self.signing_key_id = signing_key_id
        self.api_url = api_url.rstrip("/")
        self.fernet_key = fernet_key
        self._private_key_hex: str | None = None
        self._user_id: str | None = None
        self._http = httpx.Client(
            base_url=self.api_url,
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=60.0,
        )

    def _ensure_keys(self):
        """Fetch and decrypt signing key if not already cached."""
        if self._private_key_hex:
            return

        if not self._user_id:
            resp = self._http.get("/api/v1/auth/me")
            resp.raise_for_status()
            self._user_id = resp.json()["id"]

        resp = self._http.get(f"/api/v1/keys/signing-keys/{self.signing_key_id}/private")
        resp.raise_for_status()
        data = resp.json()

        if self.fernet_key:
            self._private_key_hex = decrypt_private_key(data["encrypted_private_key"], self.fernet_key)
        else:
            self._private_key_hex = decrypt_private_key(
                data["encrypted_private_key"],
                os.environ.get("TECTRA_FERNET_KEY", ""),
            )

    def sign(
        self,
        image_path: str,
        output_path: str | None = None,
        origin_type_code: str | None = None,
        device_id: str | None = None,
    ) -> dict:
        """Sign an image locally, embed watermark, register with backend.

        Args:
            image_path: Path to the image file.
            output_path: Where to save the watermarked image. Defaults to <name>_signed.<ext>.
            origin_type_code: Override origin type for this content.
            device_id: Override device ID for this content.

        Returns:
            Registration response from the backend.
        """
        self._ensure_keys()

        image_bytes = Path(image_path).read_bytes()
        content_type = "image/png"
        if image_path.lower().endswith(".jpg") or image_path.lower().endswith(".jpeg"):
            content_type = "image/jpeg"
        elif image_path.lower().endswith(".webp"):
            content_type = "image/webp"

        result = sign_image_locally(image_bytes, self._private_key_hex, self._user_id)

        if not output_path:
            p = Path(image_path)
            output_path = str(p.parent / f"{p.stem}_signed.png")
        Path(output_path).write_bytes(result["watermarked_bytes"])

        resp = self._http.post("/api/v1/register", json={
            "sha256_hash": result["sha256_hash"],
            "perceptual_hash": result["perceptual_hash"],
            "signature_hex": result["signature_hex"],
            "watermark_payload_hex": result["watermark_payload_hex"],
            "signing_key_id": self.signing_key_id,
            "origin_type_code": origin_type_code,
            "device_id": device_id,
            "file_name": Path(image_path).name,
            "file_size": result["file_size"],
            "content_type": content_type,
        })
        resp.raise_for_status()

        reg = resp.json()
        logger.info("Signed %s -> %s (record: %s)", image_path, output_path, reg["record_id"])
        return {
            "record_id": reg["record_id"],
            "blockchain_tx_hash": reg.get("blockchain_tx_hash"),
            "output_path": output_path,
            **{k: v for k, v in result.items() if k != "watermarked_bytes"},
        }

    def sign_video(
        self,
        video_path: str,
        output_path: str | None = None,
        keyframe_fps: int = 1,
        origin_type_code: str | None = None,
    ) -> dict:
        """Sign a video: extract keyframes, watermark each, reassemble, register all."""
        self._ensure_keys()
        from tectravision_sdk.video import extract_keyframes, reassemble_video

        keyframes = extract_keyframes(video_path, fps=keyframe_fps)
        if not keyframes:
            raise ValueError(f"No frames extracted from {video_path}")

        video_bytes = Path(video_path).read_bytes()
        video_sha256 = compute_sha256(video_bytes)

        # Register parent video
        frame_phashes = []
        for _, fb in keyframes:
            try:
                frame_phashes.append(compute_perceptual_hash(fb))
            except Exception:
                pass
        video_phash = frame_phashes[len(frame_phashes) // 2] if frame_phashes else "0" * 16

        from tectravision_sdk.signer import sign_message
        import hashlib
        from datetime import datetime, timezone

        timestamp = datetime.now(timezone.utc)
        fingerprint = f"{video_sha256}|{video_phash}|{int(timestamp.timestamp())}|{self._user_id}".encode()
        signature = sign_message(self._private_key_hex, fingerprint)
        watermark_payload = hashlib.sha256(signature).digest()[:16]

        resp = self._http.post("/api/v1/register", json={
            "sha256_hash": video_sha256,
            "perceptual_hash": video_phash,
            "signature_hex": signature.hex(),
            "watermark_payload_hex": watermark_payload.hex(),
            "signing_key_id": self.signing_key_id,
            "origin_type_code": origin_type_code,
            "file_name": Path(video_path).name,
            "file_size": len(video_bytes),
            "content_type": "video/mp4",
        })
        resp.raise_for_status()
        parent_id = resp.json()["record_id"]

        # Sign each keyframe
        from tectravision_sdk.signer import embed_watermark
        watermarked_frames = {}
        for frame_idx, frame_bytes in keyframes:
            wm_frame = embed_watermark(frame_bytes, watermark_payload)
            watermarked_frames[frame_idx] = wm_frame

            frame_sha = compute_sha256(frame_bytes)
            frame_ph = compute_perceptual_hash(frame_bytes)
            self._http.post("/api/v1/register", json={
                "sha256_hash": frame_sha,
                "perceptual_hash": frame_ph,
                "signature_hex": signature.hex(),
                "watermark_payload_hex": watermark_payload.hex(),
                "signing_key_id": self.signing_key_id,
                "origin_type_code": origin_type_code,
                "file_name": f"{Path(video_path).name}_frame_{frame_idx}.png",
                "file_size": len(frame_bytes),
                "content_type": "image/png",
                "parent_id": parent_id,
                "frame_index": frame_idx,
            })

        if not output_path:
            p = Path(video_path)
            output_path = str(p.parent / f"{p.stem}_signed.mp4")

        reassemble_video(watermarked_frames, video_path, output_path)
        logger.info("Signed video %s -> %s (%d frames)", video_path, output_path, len(keyframes))

        return {
            "record_id": parent_id,
            "output_path": output_path,
            "frames_signed": len(keyframes),
        }

    def verify(self, file_path: str) -> dict:
        """Verify a file by uploading it to the backend."""
        content_type = "image/png"
        ext = Path(file_path).suffix.lower()
        type_map = {
            ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
            ".png": "image/png", ".webp": "image/webp",
            ".mp4": "video/mp4", ".webm": "video/webm",
            ".mov": "video/quicktime",
        }
        content_type = type_map.get(ext, "image/png")

        with open(file_path, "rb") as f:
            resp = self._http.post(
                "/api/v1/verify",
                files={"file": (Path(file_path).name, f, content_type)},
            )
        resp.raise_for_status()
        return resp.json()

    def watch(self, directory: str, callback=None, patterns=None):
        """Watch a directory and auto-sign new files."""
        from tectravision_sdk.watcher import DirectoryWatcher
        watcher = DirectoryWatcher(
            client=self,
            directory=directory,
            callback=callback,
            patterns=patterns or ["*.jpg", "*.jpeg", "*.png", "*.mp4"],
        )
        watcher.start()
        return watcher
