from flask import Blueprint, request, jsonify
import logging
import os
from datetime import datetime
import pytz
from firebase.firebase import Firebase
from utility.authorization import TokenAuthorization

logging.basicConfig(level=logging.INFO)

sender = Blueprint("sender", __name__, url_prefix="/api")

fb = Firebase(host=os.environ.get("FIREBASE_HOST"))
timezone = pytz.timezone("Asia/Bangkok")

SMS_REQUIRED_FIELDS = ["id", "provider", "display_name", "sender_value", "type", "status"]
SMS_TYPE_CHOICES = {"alphanumeric", "long_number", "short_code"}
STATUS_CHOICES = {"active", "inactive"}

EMAIL_REQUIRED_FIELDS = [
    "id",
    "provider",
    "display_name",
    "from_email",
    "from_name",
    "status",
]


def _now_iso():
    return datetime.now(timezone).isoformat()


def _success(data, status_code=200):
    return jsonify({"status": "0000", "data": data}), status_code


def _error(message, status_code=400):
    return jsonify({"status": "8000", "message": message, "data": {}}), status_code


def _require_auth():
    token = request.headers.get("Authorization")
    if not token:
        return None, _error("Authorization header required", 401)

    bearer = token.replace("Bearer ", "")
    auth = TokenAuthorization(access_token=bearer)
    user_data = auth.validate()
    if not user_data:
        return None, _error("Unauthorized", 401)
    return user_data, None


def _check_property_access(user_data, property_id):
    try:
        user_properties = user_data.get("property")
    except Exception:
        user_properties = None
    if not user_properties or property_id not in user_properties:
        return _error("You not have permission to this property", 403)
    return None


def _sms_ref(property_id):
    return fb.db.reference().child(f"account/{property_id}/Senders/SMS")


def _email_ref(property_id):
    return fb.db.reference().child(f"account/{property_id}/Senders/Email")


def _parse_pagination():
    try:
        limit = int(request.args.get("limit", "0"))
    except ValueError:
        return None, None, _error("limit must be integer", 400)
    try:
        offset = int(request.args.get("offset", "0"))
    except ValueError:
        return None, None, _error("offset must be integer", 400)
    if limit < 0 or offset < 0:
        return None, None, _error("limit/offset must be >= 0", 400)
    return limit, offset, None


def _validate_sms_payload(data, partial=False):
    if not isinstance(data, dict):
        return "Request body must be JSON object"
    if not partial:
        for field in SMS_REQUIRED_FIELDS:
            if field not in data or data.get(field) in (None, ""):
                return f"{field} is required"
    if "type" in data and data["type"] not in SMS_TYPE_CHOICES:
        return f"type must be one of {', '.join(SMS_TYPE_CHOICES)}"
    if "status" in data and data["status"] not in STATUS_CHOICES:
        return f"status must be one of {', '.join(STATUS_CHOICES)}"
    return None


def _validate_email_payload(data, partial=False):
    if not isinstance(data, dict):
        return "Request body must be JSON object"
    if not partial:
        for field in EMAIL_REQUIRED_FIELDS:
            if field not in data or data.get(field) in (None, ""):
                return f"{field} is required"
    if "status" in data and data["status"] not in STATUS_CHOICES:
        return f"status must be one of {', '.join(STATUS_CHOICES)}"
    return None


def _list_response(ref):
    raw = ref.get()
    if not raw:
        return []
    result = []
    for sender_id, payload in raw.items():
        item = payload or {}
        item["id"] = sender_id
        result.append(item)
    return result


@sender.route("/properties/<property_id>/sms-senders", methods=["GET", "POST"])
def sms_senders(property_id):
    user_data, auth_err = _require_auth()
    if auth_err:
        return auth_err

    perm_err = _check_property_access(user_data, property_id)
    if perm_err:
        return perm_err

    if request.method == "GET":
        limit, offset, pag_err = _parse_pagination()
        if pag_err:
            return pag_err

        senders = _list_response(_sms_ref(property_id))
        if offset:
            senders = senders[offset:]
        if limit:
            senders = senders[:limit]
        return _success(senders)

    # POST create
    data = request.get_json() or {}

    validation = _validate_sms_payload(data)
    if validation:
        return _error(validation, 400)

    sender_id = data["id"]
    ref = _sms_ref(property_id).child(sender_id)
    if ref.get():
        return _error("id already exists", 400)

    now_iso = _now_iso()
    record = {
        "id": sender_id,
        "channel": "sms",
        "provider": data["provider"],
        "display_name": data["display_name"],
        "sender_value": data["sender_value"],
        "country": data.get("country"),
        "type": data["type"],
        "provider_account_id": data.get("provider_account_id"),
        "status": data["status"],
        "created_at": now_iso,
        "updated_at": now_iso,
    }
    ref.set(record)
    return _success(record, 200)


@sender.route("/properties/<property_id>/sms-senders/<sender_id>", methods=["PUT", "DELETE"])
def sms_sender_detail(property_id, sender_id):
    user_data, auth_err = _require_auth()
    if auth_err:
        return auth_err

    data = request.get_json() or {}
    perm_err = _check_property_access(user_data, property_id)
    if perm_err:
        return perm_err

    ref = _sms_ref(property_id).child(sender_id)
    existing = ref.get()
    if not existing:
        return _error("not found", 404)

    if request.method == "DELETE":
        ref.delete()
        return _success(existing, 200)

    # PUT update (partial)
    validation = _validate_sms_payload(data, partial=True)
    if validation:
        return _error(validation, 400)

    updated = dict(existing)
    allowed_fields = {
        "provider",
        "display_name",
        "sender_value",
        "country",
        "type",
        "provider_account_id",
        "status",
    }
    for key in allowed_fields:
        if key in data and data[key] is not None:
            updated[key] = data[key]
    updated["channel"] = "sms"
    updated["id"] = sender_id
    updated["updated_at"] = _now_iso()
    # preserve created_at
    if "created_at" not in updated and "created_at" in existing:
        updated["created_at"] = existing["created_at"]
    ref.set(updated)
    return _success(updated, 200)


@sender.route("/properties/<property_id>/email-senders", methods=["GET", "POST"])
def email_senders(property_id):
    user_data, auth_err = _require_auth()
    if auth_err:
        return auth_err

    perm_err = _check_property_access(user_data, property_id)
    if perm_err:
        return perm_err

    if request.method == "GET":
        limit, offset, pag_err = _parse_pagination()
        if pag_err:
            return pag_err

        senders = _list_response(_email_ref(property_id))
        if offset:
            senders = senders[offset:]
        if limit:
            senders = senders[:limit]
        return _success(senders)

    # POST create
    data = request.get_json() or {}

    validation = _validate_email_payload(data)
    if validation:
        return _error(validation, 400)

    sender_id = data["id"]
    ref = _email_ref(property_id).child(sender_id)
    if ref.get():
        return _error("id already exists", 400)

    now_iso = _now_iso()
    record = {
        "id": sender_id,
        "channel": "email",
        "provider": data["provider"],
        "display_name": data["display_name"],
        "from_email": data["from_email"],
        "from_name": data["from_name"],
        "reply_to_email": data.get("reply_to_email"),
        "domain": data.get("domain"),
        "provider_account_id": data.get("provider_account_id"),
        "status": data["status"],
        "created_at": now_iso,
        "updated_at": now_iso,
    }
    ref.set(record)
    return _success(record, 200)


@sender.route("/properties/<property_id>/email-senders/<sender_id>", methods=["PUT", "DELETE"])
def email_sender_detail(property_id, sender_id):
    user_data, auth_err = _require_auth()
    if auth_err:
        return auth_err

    data = request.get_json() or {}
    perm_err = _check_property_access(user_data, property_id)
    if perm_err:
        return perm_err

    ref = _email_ref(property_id).child(sender_id)
    existing = ref.get()
    if not existing:
        return _error("not found", 404)

    if request.method == "DELETE":
        ref.delete()
        return _success(existing, 200)

    validation = _validate_email_payload(data, partial=True)
    if validation:
        return _error(validation, 400)

    updated = dict(existing)
    allowed_fields = {
        "provider",
        "display_name",
        "from_email",
        "from_name",
        "reply_to_email",
        "domain",
        "provider_account_id",
        "status",
    }
    for key in allowed_fields:
        if key in data and data[key] is not None:
            updated[key] = data[key]
    updated["channel"] = "email"
    updated["id"] = sender_id
    updated["updated_at"] = _now_iso()
    if "created_at" not in updated and "created_at" in existing:
        updated["created_at"] = existing["created_at"]
    ref.set(updated)
    return _success(updated, 200)