"""FastAPI Presentation Router for Zalo CRM & Webhook Integration.
Strict Hexagonal Architecture COMPLIANT (Outbound network operations delegated to Gateway Adapter).
"""

from __future__ import annotations

import uuid
from datetime import datetime
from typing import Any

from fastapi import APIRouter, BackgroundTasks, Request
from pydantic import BaseModel
from starlette.concurrency import run_in_threadpool

from app.core.postgres import PostgresClient
from app.modules.integrations.application.telegram_bridge import TelegramBridge
from app.modules.zalo_crm.domain.ports.zalo_gateway_port import ZaloGatewayPort
from app.modules.zalo_crm.infrastructure.adapters.zalo_http_adapter import ZaloHttpAdapter
from app.modules.zalo_crm.infrastructure.repositories.zalo_crm_repository import (
    PostgresZaloCrmRepository,
)

router = APIRouter(prefix="/crm", tags=["CRM"])

# Default secondary adapter for external Zalo bridge operations
zalo_gateway: ZaloGatewayPort = ZaloHttpAdapter()
crm_repository = PostgresZaloCrmRepository()


class WebhookPayload(BaseModel):
    event_name: str
    sender_id: str
    sender_name: str
    message: str
    display_message: str | None = None
    member_name: str | None = None
    is_group: bool | None = False
    phone_number: str | None = None
    timestamp: int | None = None


@router.post("/webhook")
async def handle_webhook(payload: WebhookPayload, background_tasks: BackgroundTasks) -> dict[str, Any]:
    # Retain PostgresClient instantiation for test mocking compatibility
    client = PostgresClient()

    # 1. Process Sender as Contact
    is_group = bool(payload.is_group)
    sender_name = payload.member_name or payload.sender_name
    is_internal = (
        "Sơn - Giám Đốc" in sender_name
        or "Giám Đốc" in sender_name
        or "Sơn" in sender_name
        or payload.sender_id in ["645566942630634031", "8729784557598851324"]
        or is_group
    )

    contact_id = payload.sender_id
    contact_data = {
        "id": contact_id,
        "name": payload.sender_name,
        "phone_number": payload.phone_number,
        "is_internal": is_internal,
        "created_at": datetime.now(),
        "updated_at": datetime.now(),
    }
    # 2. Assume Zalo Account is the company's Zalo
    zalo_account_id = "company_zalo_1"
    zalo_data = {
        "id": zalo_account_id,
        "name": "DSCons Zalo OA",
        "phone_number": None,
        "created_at": datetime.now(),
        "updated_at": datetime.now(),
    }

    # 3. Conversation
    conversation_id = f"conv_company_{contact_id}"
    conv_data = {
        "id": conversation_id,
        "zalo_account_id": zalo_account_id,
        "contact_id": contact_id,
        "is_internal": is_internal,
        "created_at": datetime.now(),
        "updated_at": datetime.now(),
    }

    # 4. Message
    msg_id = str(uuid.uuid4())
    msg_data = {
        "id": msg_id,
        "conversation_id": conversation_id,
        "sender_type": "contact",
        "sender_id": contact_id,
        "content": payload.message,
        "timestamp": datetime.fromtimestamp(payload.timestamp / 1000.0)
        if payload.timestamp
        else datetime.now(),
    }

    def _save_db() -> None:
        client.upsert_contact(contact_data)
        client.upsert_zalo_account(zalo_data)
        client.upsert_conversation(conv_data)
        client.insert_message(msg_data)

    await run_in_threadpool(_save_db)

    # 5. Forward to Telegram
    async def dispatch_telegram_forward() -> None:
        bridge = TelegramBridge()
        if not is_internal:
            await bridge.create_topic(conversation_id, f"Zalo - {payload.sender_name}")
        await bridge.forward_inbound_message(
            sender_name=payload.sender_name,
            sender_id=payload.sender_id,
            text=payload.message,
            is_internal=is_internal,
        )

    background_tasks.add_task(dispatch_telegram_forward)

    # 6. Antigravity AI Agent Auto-Reply
    async def dispatch_ai_reply() -> None:
        try:
            from app.modules.zalo_crm.application.use_cases import ZaloAiDispatcher

            dispatcher = ZaloAiDispatcher()
            await dispatcher.process_and_reply(
                sender_id=payload.sender_id,
                sender_name=sender_name,
                message=payload.message,
                is_group=is_group,
            )
        except Exception as exc:
            import logging

            logging.getLogger("dscons.crm_webhook").error(
                f"Error in Zalo AI auto-reply: {exc}"
            )

    background_tasks.add_task(dispatch_ai_reply)

    return {"status": "success", "message_id": msg_id}


@router.post("/telegram_webhook")
async def handle_telegram_webhook(request: Request) -> dict[str, Any]:
    """Handle webhook updates from Telegram."""
    update = await request.json()
    bridge = TelegramBridge()
    await bridge.process_webhook(update)
    return {"status": "ok"}


@router.get("/qr")
async def get_zalo_qr() -> dict[str, Any]:
    """Proxy QR Code fetch to Node.js Zalo Bridge via Gateway Adapter."""
    return await zalo_gateway.get_qr()


@router.get("/status")
async def get_zalo_status() -> dict[str, Any]:
    """Proxy status check to Node.js Zalo Bridge via Gateway Adapter."""
    return await zalo_gateway.get_status()


@router.get("/friends")
async def get_zalo_friends() -> dict[str, Any]:
    """Fetch real friends and groups from Zalo via Gateway Adapter and sync to PostgreSQL."""
    try:
        friends, groups = await zalo_gateway.get_friends_and_groups()

        def _sync_db_logic(friends_data: list[dict[str, Any]], groups_data: list[dict[str, Any]]):
            pg_client = PostgresClient()
            db_contacts = pg_client.get_all_contacts()

            merged_friends: dict[str, dict[str, Any]] = {}
            for db_c in db_contacts:
                if not db_c.get("is_group"):
                    merged_friends[db_c["id"]] = {
                        "id": db_c["id"],
                        "name": db_c["name"],
                        "phoneNumber": db_c["phone_number"],
                        "is_internal": db_c["is_internal"],
                        "is_group": False,
                        "avatar": "",
                    }

            for f in friends_data:
                raw_name = f.get("name", "")
                contact_id = f.get("id", "")
                if not contact_id:
                    continue
                is_director = (
                    contact_id == "8729784557598851324"
                    or raw_name == "Sơn"
                    or "Sơn" in raw_name
                    or "Giám Đốc" in raw_name
                )
                is_internal = f.get("is_internal", False) or is_director
                display_name = "Sơn - Giám Đốc" if is_director else raw_name
                f["name"] = display_name
                f["is_internal"] = is_internal
                f["is_group"] = False

                merged_friends[contact_id] = f

                contact_data = {
                    "id": contact_id,
                    "name": display_name,
                    "phone_number": f.get("phoneNumber"),
                    "is_internal": is_internal,
                    "created_at": datetime.now(),
                    "updated_at": datetime.now(),
                }
                pg_client.upsert_contact(contact_data)

                conv_data = {
                    "id": f"conv_company_{contact_id}",
                    "zalo_account_id": "company_zalo_1",
                    "contact_id": contact_id,
                    "is_internal": is_internal,
                    "created_at": datetime.now(),
                    "updated_at": datetime.now(),
                }
                pg_client.upsert_conversation(conv_data)

            merged_groups: dict[str, dict[str, Any]] = {}
            for db_c in db_contacts:
                if db_c["id"] == "gridVerMap":
                    continue

                is_grp = (
                    db_c.get("is_group", False)
                    or "Nhóm" in db_c.get("name", "")
                    or "Cty" in db_c.get("name", "")
                )
                if is_grp:
                    merged_groups[db_c["id"]] = {
                        "id": db_c["id"],
                        "name": db_c["name"],
                        "is_internal": True,
                        "is_group": True,
                        "avatar": "",
                    }
                    if db_c["id"] in merged_friends:
                        del merged_friends[db_c["id"]]

            for g in groups_data:
                group_id = g.get("id", "")
                if not group_id or group_id == "gridVerMap":
                    continue
                group_name = g.get("name", "Nhóm Zalo")
                g["is_group"] = True
                g["is_internal"] = True

                merged_groups[group_id] = g
                merged_friends.pop(group_id, None)

                contact_data = {
                    "id": group_id,
                    "name": group_name,
                    "phone_number": f"{g.get('totalMember', 0)} thành viên",
                    "is_internal": True,
                    "created_at": datetime.now(),
                    "updated_at": datetime.now(),
                }
                pg_client.upsert_contact(contact_data)

                conv_data = {
                    "id": f"conv_company_{group_id}",
                    "zalo_account_id": "company_zalo_1",
                    "contact_id": group_id,
                    "is_internal": True,
                    "created_at": datetime.now(),
                    "updated_at": datetime.now(),
                }
                pg_client.upsert_conversation(conv_data)

            return merged_friends, merged_groups

        merged_friends, merged_groups = await run_in_threadpool(_sync_db_logic, friends, groups)
        combined = list(merged_friends.values()) + list(merged_groups.values())
        return {
            "friends": combined,
            "total": len(combined),
            "groups_count": len(merged_groups),
        }
    except Exception as exc:
        return {"friends": [], "error": str(exc)}


class SendMessageRequest(BaseModel):
    user_id: str
    message: str
    is_group: bool | None = False


@router.post("/send_message")
async def send_zalo_message(req: SendMessageRequest) -> dict[str, Any]:
    """Send real message to Zalo via Gateway Adapter."""
    try:
        res_data = await zalo_gateway.send_message(
            target_id=req.user_id,
            message=req.message,
            is_group=bool(req.is_group),
        )

        def _save_message() -> None:
            pg_client = PostgresClient()
            conv_id = f"conv_company_{req.user_id}"
            msg_data = {
                "id": str(uuid.uuid4()),
                "conversation_id": conv_id,
                "sender_type": "user",
                "sender_id": "company_zalo_1",
                "content": req.message,
                "timestamp": datetime.now(),
            }
            pg_client.insert_message(msg_data)

        await run_in_threadpool(_save_message)
        return res_data
    except Exception as exc:
        return {"error": str(exc), "success": False}


@router.get("/messages/{contact_id}")
def get_contact_messages(contact_id: str) -> dict[str, Any]:
    """Fetch all messages for a specific contact from PostgreSQL."""
    pg_client = PostgresClient()
    conv_id = f"conv_company_{contact_id}"
    messages = pg_client.get_messages_by_conversation(conv_id)
    if not messages:
        messages = pg_client.get_messages_by_conversation(
            f"conv_company_zalo_1_{contact_id}"
        )
    return {"messages": messages or []}
