"""
media_routes.py

Purpose:
  Serve user-owned images through signed URLs instead of exposing /static/User-photos directly.
  Requires the user to be authenticated and to own the camera the image belongs to.

Routes:
  - GET /media/<token>

Security:
  - Token is an HMAC of the normalized relative path under User-photos using SECRET_KEY
  - No expiry to remain stable; access still requires session auth + ownership check
  - Prevents enumeration of /static/User-photos and direct linking
"""

import os
import base64
import hmac
import hashlib
from flask import Blueprint, abort, send_file, session, current_app
from .db import get_db
from .paths import STATIC_PATH
from .helpers import parse_ts_from_any, normalize_to_static_user_photos, resolve_share_token


bp = Blueprint('media_routes', __name__)


def _b64url_decode(data: str) -> bytes:
    padding = '=' * (-len(data) % 4)
    return base64.urlsafe_b64decode(data + padding)


@bp.route('/media/<path:token>')
def media_get(token: str):
    # Two token modes: session-required (stable) or public share (expiring)
    rel = None
    is_public = False

    # Detect public share token: has two dots → three parts
    if token.count('.') == 2:
        resolved = resolve_share_token(token)
        if not resolved:
            abort(403)
        rel, exp = resolved
        # Expiry check
        import time as _t
        if _t.time() > exp:
            abort(410)  # Gone
        is_public = True
    else:
        # Session token requires login and admin/user ownership
        user_id = session.get('user_id')
        if not user_id:
            abort(401)
        # Verify session token HMAC
        if '.' not in token:
            abort(400)
        b64_rel, b64_mac = token.split('.', 1)
        try:
            rel = _b64url_decode(b64_rel).decode('utf-8')
        except Exception:
            abort(400)
        rel = normalize_to_static_user_photos(rel)
        secret = (current_app.config.get('SECRET_KEY') or '').encode('utf-8')
        expected = hmac.new(secret, rel.encode('utf-8'), hashlib.sha256).digest()
        try:
            provided = _b64url_decode(b64_mac)
        except Exception:
            abort(400)
        if not hmac.compare_digest(expected, provided):
            abort(403)

    # Ownership check by parsing camera id from filename (session mode only)
    _, cam = parse_ts_from_any(rel)
    if not cam:
        abort(404)
    db = get_db()
    if not is_public:
        owner = db.execute('SELECT 1 FROM cameras WHERE user_id=? AND camera_id=?', (session['user_id'], cam)).fetchone()
        if not owner:
            # Allow admins to view any user's media via admin UI
            row = db.execute('SELECT is_admin FROM users WHERE id=?', (session['user_id'],)).fetchone()
            if not row or int(row['is_admin'] or 0) != 1:
                abort(403)

    # Serve file if under STATIC_PATH
    abs_path = os.path.join(STATIC_PATH, rel)
    real_abs = os.path.realpath(abs_path)
    if not real_abs.startswith(os.path.realpath(STATIC_PATH)):
        abort(400)
    if not os.path.exists(real_abs):
        abort(404)
    # Use send_file to stream; set caching headers short-lived
    resp = send_file(real_abs)
    resp.headers['Cache-Control'] = 'private, max-age=300'
    return resp


