# routes/voipms.py

import json
import hmac, hashlib
import phonenumbers
from datetime import datetime
from flask import Blueprint, request, jsonify
from config import YEASTAR_WEBHOOK_URL, YEASTAR_SECRET, ENDPOINT_OBSCURITY
import requests
import logging
import uuid

bp = Blueprint("voipms", __name__)

@bp.route(f"/{ENDPOINT_OBSCURITY}/voipms-inbound/verbose", methods=["POST"])
@bp.route(f"/{ENDPOINT_OBSCURITY}/voipms-inbound", methods=["POST"])
def voipms_inbound():
    request_id = uuid.uuid4().hex[:8]
    verbose = request.path.endswith("/verbose")

    def get_client_ip():
        for header in ["X-Forwarded-For", "X-Real-IP"]:
            ip = request.headers.get(header)
            if ip:
                return ip.split(",")[0].strip()
        return request.remote_addr or "unknown"

    client_ip = get_client_ip()

    if verbose: print(f"[{request_id}] voipms_inbound called{' [VERBOSE]' if verbose else ''}")

    try:
        if verbose:
            print(f"[{request_id}] Headers: {dict(request.headers)}")

        raw_data = request.get_data(as_text=True)
        if verbose:
            print(f"[{request_id}] Raw Body: {raw_data}")

        data = request.get_json(force=True)

        payload = data.get("data", {}).get("payload", {})
        from_number = payload.get("from", {}).get("phone_number")
        to_list = payload.get("to", [])
        text = payload.get("text", "")
        media_urls = [m["url"] for m in payload.get("media", [])] if payload.get("media") else []

        from_number = to_e164(from_number) if from_number else ""
        to_numbers = [to_e164(entry.get("phone_number")) for entry in to_list if entry.get("phone_number")]

        if verbose:
            print(f"[{request_id}] Normalized From: {from_number}")
            print(f"[{request_id}] Normalized To: {to_numbers}")
            print(f"[{request_id}] Text: {text}")
            print(f"[{request_id}] Media URLs: {media_urls}")
        else:
            msg_type = "MMS" if media_urls else "SMS"
            now_str = datetime.now().isoformat()
            print(f"[{now_str}] IP:{client_ip} From Voip.ms | {msg_type} | From:{from_number} ? To:{', '.join(to_numbers)} | Images:{len(media_urls)}")

        ys_payload = create_yeastar_payload({
            "from": from_number,
            "to": to_numbers,
            "text": text,
            "media_urls": media_urls
        })

        if verbose:
            print(f"[{request_id}] Outbound Payload: {json.dumps(ys_payload, indent=2)}")

        body_str = json.dumps(ys_payload)
        signature = generate_signature(body_str)
        headers = {
            "Content-Type": "application/json",
            "X-Signature-256": signature
        }

        response = requests.post(YEASTAR_WEBHOOK_URL, data=body_str, headers=headers)
        if verbose: print(f"[{request_id}] Yeastar Response Code: {response.status_code}")
        if verbose:
            print(f"[{request_id}] Yeastar Response Body: {response.text}")

        return jsonify({"status": "ok"}), 200

    except Exception as e:
        logging.error(f"[{request_id}] Error in voipms_inbound: {e}", exc_info=True)
        return jsonify({"error": "internal server error"}), 500

def generate_signature(body: str) -> str:
    signature = hmac.new(YEASTAR_SECRET.encode(), body.encode(), hashlib.sha256).hexdigest()
    return f"sha256={signature}"

def to_e164(number):
    try:
        parsed = phonenumbers.parse(number, "US")
        return phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)
    except Exception as e:
        logging.warning(f"Failed to normalize phone number {number}: {e}")
        return number

def create_yeastar_payload(data):
    now_iso = datetime.now().astimezone().isoformat()
    message_id = str(int(datetime.utcnow().timestamp()))
    payload = {
        "data": {
            "event_type": "message.received",
            "payload": {
                "id": message_id,
                "from": {
                    "phone_number": data["from"]
                },
                "to": [
                    {"phone_number": num} for num in data["to"]
                ],
                "text": data["text"],
                "record_type": "message",
                "received_at": now_iso
            }
        }
    }

    media_urls = data.get("media_urls", [])
    if media_urls:
        payload["data"]["payload"].pop("text", None)
        payload["data"]["payload"]["media"] = [{"url": url} for url in media_urls]

    return payload
